home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xmcd-1.4 / libdi.d / slioc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-10  |  67.5 KB  |  3,628 lines

  1. /*
  2.  *   libdi - CD Audio Player Device Interface Library
  3.  *
  4.  *   Copyright (C) 1995  Ti Kan
  5.  *   E-mail: ti@amb.org
  6.  *
  7.  *   This program is free software; you can redistribute it and/or modify
  8.  *   it under the terms of the GNU General Public License as published by
  9.  *   the Free Software Foundation; either version 2 of the License, or
  10.  *   (at your option) any later version.
  11.  *
  12.  *   This program is distributed in the hope that it will be useful,
  13.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *   GNU General Public License for more details.
  16.  *
  17.  *   You should have received a copy of the GNU General Public License
  18.  *   along with this program; if not, write to the Free Software
  19.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  */
  21.  
  22. /*
  23.  * SunOS/Linux ioctl method module
  24.  *
  25.  * Contributing author: Peter Bauer
  26.  * E-mail: 100136.3530@compuserve.com
  27.  */
  28.  
  29. #ifndef LINT
  30. static char *_slioc_c_ident_ = "@(#)slioc.c    5.32.1 95/03/04";
  31. #endif
  32.  
  33. #include "common.d/appenv.h"
  34. #include "common.d/util.h"
  35. #include "libdi.d/libdi.h"
  36. #include "libdi.d/slioc.h"
  37.  
  38. #define CLIP_FRAMES    10
  39.  
  40. #if defined(DI_SLIOC) && !defined(DEMO_ONLY)
  41.  
  42. extern appdata_t    app_data;
  43. extern FILE        *errfp;
  44.  
  45.  
  46. STATIC bool_t    slioc_run_ab(curstat_t *),
  47.         slioc_run_sample(curstat_t *),
  48.         slioc_run_prog(curstat_t *),
  49.         slioc_run_repeat(curstat_t *),
  50.         slioc_disc_ready(curstat_t *),
  51.         slioc_disc_present(bool_t),
  52.         slioc_open(char *);
  53. STATIC void    slioc_stat_poll(curstat_t *),
  54.         slioc_insert_poll(curstat_t *),
  55.         slioc_close(void);
  56.  
  57.  
  58. STATIC int    slioc_fd = -1,            /* CD-ROM file descriptor */
  59.         slioc_stat_interval;        /* Status poll interval */
  60. STATIC long    slioc_stat_id,            /* Play status poll timer id */
  61.         slioc_insert_id,        /* Disc insert poll timer id */
  62.         slioc_search_id;        /* FF/REW timer id */
  63. STATIC byte_t    slioc_tst_status = M_NODISC,    /* Playback status on load */
  64.         slioc_next_sam;            /* Next SAMPLE track */
  65. STATIC bool_t    slioc_not_open = TRUE,        /* Device not opened yet */
  66.         slioc_stat_polling,        /* Polling play status */
  67.         slioc_insert_polling,        /* Polling disc insert */
  68.         slioc_new_progshuf,        /* New program/shuffle seq */
  69.         slioc_start_search = FALSE,    /* Start FF/REW play segment */
  70.         slioc_idx_pause = FALSE,    /* Prev/next index pausing */
  71.         slioc_fake_stop = FALSE,    /* Force a completion status */
  72.         slioc_playing = FALSE;        /* Currently playing */
  73. STATIC word32_t    slioc_ab_start_addr,        /* A->B mode start block */
  74.         slioc_ab_end_addr,        /* A->B mode end block */
  75.         slioc_sav_end_addr;        /* Err recov saved end addr */
  76. STATIC msf_t    slioc_ab_start_msf,        /* A->B mode start MSF */
  77.         slioc_ab_end_msf,        /* A->B mode end MSF */
  78.         slioc_sav_end_msf;        /* Err recov saved end MSF */
  79. STATIC byte_t    slioc_sav_end_fmt;        /* Err recov saved end fmt */
  80.  
  81.  
  82. /* SunOS/Linux CDROM ioctl names */
  83. STATIC iocname_t iname[] = {
  84.     { CDROMSUBCHNL,        "CDROMSUBCHNL"        },
  85.     { CDROMREADTOCHDR,    "CDROMREADTOCHDR"    },
  86.     { CDROMREADTOCENTRY,    "CDROMREADTOCENTRY"    },
  87. #ifdef CDROMLOAD
  88.     { CDROMLOAD,        "CDROMLOAD"        },
  89. #endif
  90.     { CDROMEJECT,        "CDROMEJECT"        },
  91.     { CDROMSTART,        "CDROMSTART"        },
  92.     { CDROMSTOP,        "CDROMSTOP"        },
  93.     { CDROMPAUSE,        "CDROMPAUSE"        },
  94.     { CDROMRESUME,        "CDROMRESUME"        },
  95.     { CDROMVOLCTRL,        "CDROMVOLCTRL"        },
  96.     { CDROMPLAYTRKIND,    "CDROMPLAYTRKIND"    },
  97.     { CDROMPLAYMSF,        "CDROMPLAYMSF"        },
  98.     { 0,            NULL            },
  99. };
  100.  
  101.  
  102.  
  103. /***********************
  104.  *  internal routines  *
  105.  ***********************/
  106.  
  107.  
  108. /*
  109.  * slioc_send
  110.  *    Issue ioctl command.
  111.  *
  112.  * Args:
  113.  *    cmd - ioctl command
  114.  *    arg - ioctl argument
  115.  *    prnerr - whether an error message is to be displayed if the ioctl fails
  116.  *
  117.  * Return:
  118.  *    TRUE - ioctl successful
  119.  *    FALSE - ioctl failed
  120.  */
  121. STATIC bool_t
  122. slioc_send(int cmd, void *arg, bool_t prnerr)
  123. {
  124.     int    i;
  125.  
  126.     if (slioc_fd < 0)
  127.         return FALSE;
  128.  
  129.     if (app_data.debug) {
  130.         for (i = 0; iname[i].name != NULL; i++) {
  131.             if (iname[i].cmd == cmd) {
  132.                 fprintf(errfp, "\nIOCTL: %s\n",
  133.                     iname[i].name);
  134.                 break;
  135.             }
  136.         }
  137.         if (iname[i].name == NULL)
  138.             fprintf(errfp, "\nIOCTL: 0x%x\n", cmd);
  139.     }
  140.  
  141.     if (ioctl(slioc_fd, cmd, arg) < 0) {
  142.         if (prnerr) {
  143.             fprintf(errfp, "CD audio: ioctl error on %s: ",
  144.                 app_data.device);
  145.  
  146.             for (i = 0; iname[i].name != NULL; i++) {
  147.                 if (iname[i].cmd == cmd) {
  148.                     fprintf(errfp, "cmd=%s errno=%d\n",
  149.                         iname[i].name, errno);
  150.                     break;
  151.                 }
  152.             }
  153.             if (iname[i].name == NULL)
  154.                 fprintf(errfp, "cmd=0x%x errno=%d\n",
  155.                     cmd, errno);
  156.         }
  157.         return FALSE;
  158.     }
  159.  
  160.         return TRUE;
  161. }
  162.  
  163.  
  164. /*
  165.  * slioc_open
  166.  *    Open CD-ROM device
  167.  *
  168.  * Args:
  169.  *    path - device path name string
  170.  *
  171.  * Return:
  172.  *    TRUE - open successful
  173.  *    FALSE - open failed
  174.  */
  175. STATIC bool_t
  176. slioc_open(char *path)
  177. {
  178.     struct stat    stbuf;
  179.     char        errstr[ERR_BUF_SZ];
  180.     int        i,
  181.             ret;
  182.  
  183.     /* Force close on eject. */
  184.     app_data.eject_close = TRUE;
  185.  
  186.     /* Check for validity of device node */
  187.     if (stat(path, &stbuf) < 0) {
  188.         sprintf(errstr, app_data.str_staterr, path);
  189.         cd_fatal_popup(app_data.str_fatal, errstr);
  190.         return FALSE;
  191.     }
  192.  
  193. #ifdef linux
  194.     /* Linux CD-ROM device is a block special file! */
  195.     if (!S_ISBLK(stbuf.st_mode))
  196. #else
  197.     if (!S_ISCHR(stbuf.st_mode))
  198. #endif
  199.     {
  200.         sprintf(errstr, app_data.str_noderr, path);
  201.         cd_fatal_popup(app_data.str_fatal, errstr);
  202.         return FALSE;
  203.     }
  204.  
  205.     if ((slioc_fd = open(path, O_RDONLY | O_EXCL)) < 0) {
  206.         DBGPRN(errfp, "Cannot open %s: errno=%d\n", path, errno);
  207.         return FALSE;
  208.     }
  209.  
  210. #ifdef linux
  211.     /* Linux hack:  The CD-ROM driver allows the open to succeed
  212.      * even if there is no CD loaded.  We test for the existence of
  213.      * a disc with slioc_disc_present().
  214.      */
  215.     for (i = 0; i < 3; i++) {
  216.         if ((ret = slioc_disc_present(FALSE)) == TRUE)
  217.             break;
  218.     }
  219.     if (ret == FALSE) {
  220.         slioc_close();
  221.         return FALSE;
  222.     }
  223. #endif
  224.  
  225.     return TRUE;
  226. }
  227.  
  228.  
  229. /*
  230.  * slioc_close
  231.  *    Close CD-ROM device
  232.  *
  233.  * Args:
  234.  *    Nothing.
  235.  *
  236.  * Return:
  237.  *    Nothing.
  238.  */
  239. void
  240. slioc_close(void)
  241. {
  242.     if (slioc_fd >= 0) {
  243.         close(slioc_fd);
  244.         slioc_fd = -1;
  245.     }
  246. }
  247.  
  248.  
  249. /*
  250.  * slioc_rdsubq
  251.  *    Send Read Subchannel command to the device
  252.  *
  253.  * Args:
  254.  *    buf - Pointer to the return data buffer
  255.  *    msf - Whether to use MSF or logical block address format
  256.  *
  257.  * Return:
  258.  *    TRUE - success
  259.  *    FALSE - failure
  260.  */
  261. STATIC bool_t
  262. slioc_rdsubq(struct cdrom_subchnl *sub, byte_t msf)
  263. {
  264.     bool_t    ret;
  265.  
  266.         sub->cdsc_format = msf;
  267.     ret = slioc_send(CDROMSUBCHNL, sub, TRUE);
  268.  
  269.     DBGDUMP("cdrom_subchnl data bytes", (byte_t *) sub,
  270.         sizeof(struct cdrom_subchnl));
  271.  
  272.     return (ret);
  273. }
  274.  
  275.  
  276. /*
  277.  * slioc_rdtoc
  278.  *    Send Read TOC command to the device
  279.  *
  280.  * Args:
  281.  *    buf - Pointer to the return data toc header
  282.  *    h - address of pointer to array of toc entrys will be allocated
  283.  *        by this routine
  284.  *    start - Starting track number for which the TOC data is returned
  285.  *
  286.  * Return:
  287.  *    TRUE - success
  288.  *    FALSE - failure
  289.  */
  290. STATIC bool_t
  291. slioc_rdtoc(struct cdrom_tochdr *h, struct cdrom_tocentry **e, int start)
  292. {
  293.     int    i,
  294.         j;
  295.  
  296.     /* Read the TOC header first */
  297.     if (!slioc_send(CDROMREADTOCHDR, h, TRUE))
  298.         return FALSE;
  299.  
  300.     DBGDUMP("cdrom_tochdr data bytes", (byte_t *) h,
  301.         sizeof(struct cdrom_tochdr));
  302.  
  303.     if (start == 0)
  304.         start = h->cdth_trk0;
  305.  
  306.     if (start > (int) h->cdth_trk1)
  307.         return FALSE;
  308.  
  309.     h->cdth_trk1++;
  310.  
  311.     *e = (struct cdrom_tocentry *) malloc(
  312.         (h->cdth_trk1 - start + 1) * sizeof(struct cdrom_tocentry)
  313.     );
  314.  
  315.     if (*e == NULL) {
  316.         cd_fatal_popup(app_data.str_fatal, app_data.str_nomemory);
  317.         return FALSE;
  318.     }
  319.  
  320.     for (i = start; i <= (int) h->cdth_trk1; i++) {
  321.         j = i - start;
  322.  
  323.         (*e)[j].cdte_track =
  324.             (i < (int) h->cdth_trk1) ? i : CDROM_LEADOUT;
  325.  
  326.         (*e)[j].cdte_format = CDROM_MSF;
  327.  
  328.         if (!slioc_send(CDROMREADTOCENTRY, &(*e)[j], TRUE)) {
  329.             free(*e);
  330.             return FALSE;
  331.         }
  332.  
  333.         DBGDUMP("cdrom_tocentry data bytes", (byte_t *) &(*e)[j],
  334.             sizeof(struct cdrom_tocentry));
  335.  
  336.         /* Sanity check */
  337.         if ((*e)[j].cdte_track == CDROM_LEADOUT &&
  338.             (*e)[j].cdte_addr.lba == (*e)[0].cdte_addr.lba) {
  339.             free(*e);
  340.             return FALSE;
  341.         }
  342.     }
  343.  
  344.     return TRUE;
  345. }
  346.  
  347.  
  348. /*
  349.  * slioc_disc_present
  350.  *    Check if a CD is loaded.  Much of the complication in this
  351.  *    routine stems from the fact that the SunOS and the Linux
  352.  *    CD-ROM drivers behave differently when a CD is ejected.
  353.  *    In fact, the scsi, mcd, sbpcd, cdu31a drivers under Linux
  354.  *    are also inconsistent amongst each other (Argh!).
  355.  *
  356.  * Args:
  357.  *    savstat - Whether to save start-up status in slioc_tst_status.
  358.  *
  359.  * Return:
  360.  *    TRUE - success
  361.  *    FALSE - failure (drive not ready)
  362.  */
  363. STATIC bool_t
  364. slioc_disc_present(bool_t savstat)
  365. {
  366.     struct cdrom_subchnl    sub;
  367.     struct cdrom_tochdr    h;
  368.     struct cdrom_tocentry    e;
  369.     word32_t        a1,
  370.                 a2;
  371.     static int        tot_trks = 0;
  372.     static word32_t        sav_a1 = 0,
  373.                 sav_a2 = 0;
  374.  
  375.     if (savstat)
  376.         slioc_tst_status = M_NODISC;
  377.  
  378.     /* Fake it with CDROMSUBCHNL */
  379.     memset((byte_t *) &sub, 0, sizeof(sub));
  380.     sub.cdsc_format = CDROM_MSF;
  381.     if (!slioc_send(CDROMSUBCHNL, &sub, app_data.debug))
  382.         return FALSE;
  383.  
  384.     switch (sub.cdsc_audiostatus) {
  385.     case CDROM_AUDIO_PLAY:
  386.         if (savstat) {
  387.             DBGPRN(errfp, "\nstatus=CDROM_AUDIO_PLAY\n");
  388.             slioc_tst_status = M_PLAY;
  389.             return TRUE;
  390.         }
  391.         break;
  392.     case CDROM_AUDIO_PAUSED:
  393.         if (savstat) {
  394.             DBGPRN(errfp, "\nstatus=CDROM_AUDIO_PAUSED\n");
  395.             slioc_tst_status = M_PAUSE;
  396.             return TRUE;
  397.         }
  398.         break;
  399.     case CDROM_AUDIO_ERROR:
  400.         DBGPRN(errfp, "\nstatus=CDROM_AUDIO_ERROR\n");
  401.         break;
  402.     case CDROM_AUDIO_COMPLETED:
  403.         DBGPRN(errfp, "\nstatus=CDROM_AUDIO_COMPLETED\n");
  404.         break;
  405.     case CDROM_AUDIO_NO_STATUS:
  406.         DBGPRN(errfp, "\nstatus=CDROM_AUDIO_NO_STATUS\n");
  407.         break;
  408.     case CDROM_AUDIO_INVALID:
  409.         DBGPRN(errfp, "\nstatus=CDROM_AUDIO_INVALID\n");
  410.         break;
  411.     default:
  412.         DBGPRN(errfp, "\nstatus=unknown (%d)\n", sub.cdsc_audiostatus);
  413.         return FALSE;
  414.     }
  415.  
  416.     if (savstat)
  417.         slioc_tst_status = M_STOP;
  418.  
  419.     /* CDROMSUBCHNL didn't give useful info.
  420.      * Try CDROMREADTOCHDR and CDROMREADTOCENTRY.
  421.      */
  422.     memset((byte_t *) &h, 0, sizeof(h));
  423.     if (!slioc_send(CDROMREADTOCHDR, &h, app_data.debug))
  424.         return FALSE;
  425.  
  426.     if ((h.cdth_trk1 - h.cdth_trk0 + 1) != tot_trks) {
  427.         /* Disk changed */
  428.         tot_trks = h.cdth_trk1 - h.cdth_trk0 + 1;
  429.         return FALSE;
  430.     }
  431.  
  432.     memset((byte_t *) &e, 0, sizeof(e));
  433.     e.cdte_format = CDROM_MSF;
  434.     e.cdte_track = h.cdth_trk0;
  435.     if (!slioc_send(CDROMREADTOCENTRY, &e, app_data.debug))
  436.         return FALSE;
  437.  
  438.     a1 = (word32_t) e.cdte_addr.lba;
  439.  
  440.     memset((byte_t *) &e, 0, sizeof(e));
  441.     e.cdte_format = CDROM_MSF;
  442.     e.cdte_track = h.cdth_trk1;
  443.     if (!slioc_send(CDROMREADTOCENTRY, &e, app_data.debug))
  444.         return FALSE;
  445.  
  446.     a2 = (word32_t) e.cdte_addr.lba;
  447.  
  448.     DBGPRN(errfp, "\na1=0x%x a2=0x%x\n", a1, a2);
  449.  
  450.     if (a1 != sav_a1 || a2 != sav_a2) {
  451.         /* Disk changed */
  452.         sav_a1 = a1;
  453.         sav_a2 = a2;
  454.         return FALSE;
  455.     }
  456.  
  457.     if (tot_trks > 1 && a1 == a2)
  458.         return FALSE;
  459.  
  460.     return TRUE;
  461. }
  462.  
  463.  
  464. /*
  465.  * slioc_playmsf
  466.  *    Send Play Audio MSF command to the device
  467.  *
  468.  * Args:
  469.  *    start - Pointer to the starting position MSF data
  470.  *    end - Pointer to the ending position MSF data
  471.  *
  472.  * Return:
  473.  *    TRUE - success
  474.  *    FALSE - failure
  475.  */
  476. STATIC bool_t
  477. slioc_playmsf(msf_t *start, msf_t *end)
  478. {
  479.     struct cdrom_msf    m;
  480.  
  481.     m.cdmsf_min0 = start->min;
  482.     m.cdmsf_sec0 = start->sec;
  483.     m.cdmsf_frame0 = start->frame;
  484.     m.cdmsf_min1 = end->min;
  485.     m.cdmsf_sec1 = end->sec;
  486.     m.cdmsf_frame1 = end->frame;
  487.  
  488.     DBGDUMP("cdrom_msf data bytes", (byte_t *) &m,
  489.         sizeof(struct cdrom_msf));
  490.  
  491.     return (slioc_send(CDROMPLAYMSF, &m, TRUE));
  492. }
  493.  
  494.  
  495. /*
  496.  * slioc_start_stop
  497.  *    Send Start/Stop Unit command to the device
  498.  *
  499.  * Args:
  500.  *    start - Whether to start unit or stop unit
  501.  *    loej - Whether caddy load/eject operation should be performed
  502.  *
  503.  * Return:
  504.  *    TRUE - success
  505.  *    FALSE - failure
  506.  */
  507. STATIC bool_t
  508. slioc_start_stop(bool_t start, bool_t loej)
  509. {
  510.         bool_t    ret;
  511.  
  512.     if (start) {
  513.         if (loej)
  514. #ifdef CDROMLOAD
  515.             ret = slioc_send(CDROMLOAD, NULL, TRUE);
  516. #else
  517.             ret = FALSE;
  518. #endif
  519.         else
  520.             ret = slioc_send(CDROMSTART, NULL, TRUE);
  521.     }
  522.     else {
  523.         slioc_playing = FALSE;
  524.  
  525.         if (loej)
  526.             ret = slioc_send(CDROMEJECT, NULL, TRUE);
  527.         else
  528.             ret = slioc_send(CDROMSTOP, NULL, TRUE);
  529.     }
  530.  
  531.     return (ret);
  532.  
  533. }
  534.  
  535.  
  536. /*
  537.  * slioc_pause_resume
  538.  *    Send Pause/Resume command to the device
  539.  *
  540.  * Args:
  541.  *    resume - Whether to resume or pause
  542.  *
  543.  * Return:
  544.  *    TRUE - success
  545.  *    FALSE - failure
  546.  */
  547. bool_t
  548. slioc_pause_resume(bool_t resume)
  549. {
  550.     return (slioc_send(resume ? CDROMRESUME : CDROMPAUSE, NULL, TRUE));
  551. }
  552.  
  553.  
  554. /*
  555.  * slioc_play_trkidx
  556.  *    Send Play Audio Track/Index command to the device
  557.  *
  558.  * Args:
  559.  *    start_trk - Starting track number
  560.  *    start_idx - Starting index number
  561.  *    end_trk - Ending track number
  562.  *    end_idx - Ending index number
  563.  *
  564.  * Return:
  565.  *    TRUE - success
  566.  *    FALSE - failure
  567.  */
  568. bool_t
  569. slioc_play_trkidx(int start_trk, int start_idx, int end_trk, int end_idx)
  570. {
  571.     struct cdrom_ti    t;
  572.  
  573.     t.cdti_trk0 = start_trk;
  574.     t.cdti_ind0 = start_idx;
  575.     t.cdti_trk1 = end_trk;
  576.     t.cdti_ind1 = end_idx;
  577.  
  578.     DBGDUMP("cdrom_ti data bytes", (byte_t *) &t, sizeof(struct cdrom_ti));
  579.  
  580.     return (slioc_send(CDROMPLAYTRKIND, &t, TRUE));
  581. }
  582.  
  583.  
  584. /*
  585.  * slioc_do_playaudio
  586.  *    General top-level play audio function
  587.  *
  588.  * Args:
  589.  *    addr_fmt - The address formats specified:
  590.  *        ADDR_BLK: logical block address (not supported)
  591.  *        ADDR_MSF: MSF address
  592.  *        ADDR_TRKIDX: Track/index numbers
  593.  *        ADDR_OPTEND: Ending address can be ignored
  594.  *    start_addr - Starting logical block address (not supported)
  595.  *    end_addr - Ending logical block address (not supported)
  596.  *    start_msf - Pointer to start address MSF data
  597.  *    end_msf - Pointer to end address MSF data
  598.  *    trk - Starting track number
  599.  *    idx - Starting index number
  600.  *
  601.  * Return:
  602.  *    TRUE - success
  603.  *    FALSE - failure
  604.  */
  605. STATIC bool_t
  606. slioc_do_playaudio(
  607.     byte_t        addr_fmt,
  608.     word32_t    start_addr,
  609.     word32_t    end_addr,
  610.     msf_t        *start_msf,
  611.     msf_t        *end_msf,
  612.     byte_t        trk,
  613.     byte_t        idx
  614. )
  615. {
  616.     msf_t        emsf,
  617.             *emsfp = NULL;
  618.     bool_t        ret = FALSE;
  619.  
  620.  
  621.     /* Fix addresses: Some CD-ROM drives will only allow playing to
  622.      * the last frame minus a few frames.
  623.      */
  624.     if (addr_fmt & ADDR_MSF && end_msf != NULL) {
  625.         emsf = *end_msf;    /* Structure copy */
  626.         emsfp = &emsf;
  627.  
  628.         if (emsfp->frame >= CLIP_FRAMES)
  629.             emsfp->frame -= CLIP_FRAMES;
  630.         else {
  631.             if (emsfp->sec > 0)
  632.                 emsfp->sec--;
  633.             else {
  634.                 emsfp->sec = 59;
  635.                 if (emsfp->min > 0)
  636.                     emsfp->min--;
  637.             }
  638.             emsfp->frame = FRAME_PER_SEC -
  639.                 (CLIP_FRAMES - emsfp->frame);
  640.         }
  641.  
  642.         emsfp->res = start_msf->res = 0;
  643.  
  644.         /* Save end address for error recovery */
  645.         slioc_sav_end_msf = *end_msf;
  646.     }
  647.     if (addr_fmt & ADDR_BLK) {
  648.         if (end_addr >= CLIP_FRAMES)
  649.             end_addr -= CLIP_FRAMES;
  650.         else if (end_addr > 0)
  651.             end_addr = 0;
  652.  
  653.         /* Save end address for error recovery */
  654.         slioc_sav_end_addr = end_addr;
  655.     }
  656.  
  657.     /* Save end address format for error recovery */
  658.     slioc_sav_end_fmt = addr_fmt;
  659.  
  660.     if (slioc_playing)
  661.         /* Pause playback first */
  662.         (void) slioc_send(CDROMPAUSE, NULL, TRUE);
  663.     else
  664.         /* Spin up CD */
  665.         (void) slioc_send(CDROMSTART, NULL, TRUE);
  666.  
  667.     slioc_playing = TRUE;
  668.  
  669.     if ((addr_fmt & ADDR_MSF) && app_data.playmsf_supp)
  670.         ret = slioc_playmsf(start_msf, emsfp);
  671.     
  672.     if (!ret && (addr_fmt & ADDR_TRKIDX) && app_data.playti_supp)
  673.         ret = slioc_play_trkidx(trk, idx, trk, idx);
  674.  
  675.     return (ret);
  676. }
  677.  
  678.  
  679. /*
  680.  * slioc_get_playstatus
  681.  *    Obtain and update current playback status information
  682.  *
  683.  * Args:
  684.  *    s - Pointer to the curstat_t structure
  685.  *
  686.  * Return:
  687.  *    TRUE - Audio playback is in progress
  688.  *    FALSE - Audio playback stopped or command failure
  689.  */
  690. STATIC bool_t
  691. slioc_get_playstatus(curstat_t *s)
  692. {
  693.     struct cdrom_subchnl    sub;
  694.     msf_t            recov_start_msf;
  695.     word32_t        recov_start_addr;
  696.     byte_t            audio_status;
  697.     bool_t            done;
  698.     static int        errcnt = 0;
  699.     static word32_t        errblk = 0;
  700.     static bool_t        in_slioc_get_playstatus = FALSE;
  701.  
  702.  
  703.     /* Lock this routine from multiple entry */
  704.     if (in_slioc_get_playstatus)
  705.         return TRUE;
  706.  
  707.     in_slioc_get_playstatus = TRUE;
  708.  
  709.     memset((byte_t *) &sub, 0, sizeof(sub));
  710.  
  711.     if (!slioc_rdsubq(&sub, CDROM_MSF)) {
  712.         /* Check to see if the disc had been manually ejected */
  713.         if (!slioc_disc_ready(s)) {
  714.             slioc_sav_end_addr = 0;
  715.             slioc_sav_end_msf.min = 0;
  716.             slioc_sav_end_msf.sec = 0;
  717.             slioc_sav_end_msf.frame = 0;
  718.             slioc_sav_end_fmt = 0;
  719.             errcnt = 0;
  720.             errblk = 0;
  721.  
  722.             in_slioc_get_playstatus = FALSE;
  723.             return FALSE;
  724.         }
  725.  
  726.         /* The read subchannel command failed for some
  727.          * unknown reason.  Just return success and
  728.          * hope the next poll succeeds.  We don't want
  729.          * to return FALSE here because that would stop
  730.          * the poll.
  731.          */
  732.         in_slioc_get_playstatus = FALSE;
  733.         return TRUE;
  734.     }
  735.  
  736.     /* Check the subchannel data */
  737.     audio_status = sub.cdsc_audiostatus;
  738.  
  739.     if (sub.cdsc_trk != s->cur_trk) {
  740.         s->cur_trk = sub.cdsc_trk;
  741.         dpy_track(s);
  742.     }
  743.  
  744.     if (sub.cdsc_ind != s->cur_idx) {
  745.         s->cur_idx = sub.cdsc_ind;
  746.         s->sav_iaddr = s->cur_tot_addr;
  747.         dpy_index(s);
  748.     }
  749.  
  750.     s->cur_tot_frame = sub.cdsc_absaddr.msf.frame;
  751.     s->cur_tot_sec = sub.cdsc_absaddr.msf.second;
  752.     s->cur_tot_min = sub.cdsc_absaddr.msf.minute;
  753.     msftoblk(
  754.         s->cur_tot_min,
  755.         s->cur_tot_sec,
  756.         s->cur_tot_frame,
  757.         &s->cur_tot_addr,
  758.         MSF_OFFSET(s)
  759.     );
  760.  
  761.     s->cur_trk_frame = sub.cdsc_reladdr.msf.frame;
  762.     s->cur_trk_sec = sub.cdsc_reladdr.msf.second;
  763.     s->cur_trk_min = sub.cdsc_reladdr.msf.minute;
  764.     msftoblk(
  765.         s->cur_trk_min,
  766.         s->cur_trk_sec,
  767.         s->cur_trk_frame,
  768.         &s->cur_trk_addr,
  769.         0
  770.     );
  771.  
  772.     /* Update time display */
  773.     dpy_time(s, FALSE);
  774.  
  775.     /* Hack: to work around the fact that some CD-ROM drives
  776.      * return CDROM_AUDIO_PAUSED status after issuing a Stop Unit command.
  777.      * Just treat the status as completed if we get a paused status
  778.      * and we don't expect the drive to be paused.
  779.      */
  780.     if (audio_status == CDROM_AUDIO_PAUSED && s->mode != M_PAUSE &&
  781.         !slioc_idx_pause)
  782.         audio_status = CDROM_AUDIO_COMPLETED;
  783.  
  784.     /* Force completion status */
  785.     if (slioc_fake_stop)
  786.         audio_status = CDROM_AUDIO_COMPLETED;
  787.  
  788.     /* Deal with playback status */
  789.     switch (audio_status) {
  790.     case CDROM_AUDIO_PLAY:
  791.     case CDROM_AUDIO_PAUSED:
  792.         done = FALSE;
  793.  
  794.         /* If we haven't encountered an error for a while, then
  795.          * clear the error count.
  796.          */
  797.         if (errcnt > 0 && (s->cur_tot_addr - errblk) > ERR_CLRTHRESH)
  798.             errcnt = 0;
  799.         break;
  800.  
  801.     case CDROM_AUDIO_ERROR:
  802.         /* Check to see if the disc had been manually ejected */
  803.         if (!slioc_disc_ready(s)) {
  804.             slioc_sav_end_addr = 0;
  805.             slioc_sav_end_msf.min = 0;
  806.             slioc_sav_end_msf.sec = 0;
  807.             slioc_sav_end_msf.frame = 0;
  808.             slioc_sav_end_fmt = 0;
  809.             errcnt = 0;
  810.             errblk = 0;
  811.  
  812.             in_slioc_get_playstatus = FALSE;
  813.             return FALSE;
  814.         }
  815.  
  816.         /* Audio playback stopped due to a disc error.  We will
  817.          * try to restart the playback by skipping a few frames
  818.          * and continuing.  This will cause a glitch in the sound
  819.          * but is better than just stopping.
  820.          */
  821.         done = FALSE;
  822.  
  823.         /* Check for max errors limit */
  824.         if (++errcnt > MAX_RECOVERR) {
  825.             done = TRUE;
  826.             fprintf(errfp, "CD audio: %s\n", app_data.str_maxerr);
  827.         }
  828.         errblk = s->cur_tot_addr;
  829.  
  830.         if (!done && (slioc_sav_end_fmt & ADDR_MSF)) {
  831.             if ((int) s->cur_tot_frame <
  832.                 (FRAME_PER_SEC - ERR_SKIPBLKS)) {
  833.                 recov_start_msf.min = s->cur_tot_min;
  834.                 recov_start_msf.sec = s->cur_tot_sec;
  835.                 recov_start_msf.frame =
  836.                     s->cur_tot_frame + ERR_SKIPBLKS;
  837.             }
  838.             else if ((int) s->cur_tot_sec < 59) {
  839.                 recov_start_msf.min = s->cur_tot_min;
  840.                 recov_start_msf.sec = s->cur_tot_sec + 1;
  841.                 recov_start_msf.frame = ERR_SKIPBLKS -
  842.                     (FRAME_PER_SEC - s->cur_tot_frame);
  843.             }
  844.             else {
  845.                 recov_start_msf.min = s->cur_tot_min + 1;
  846.                 recov_start_msf.sec = 0;
  847.                 recov_start_msf.frame = ERR_SKIPBLKS -
  848.                     (FRAME_PER_SEC - s->cur_tot_frame);
  849.             }
  850.  
  851.             /* Check to see if we have skipped past
  852.              * the end.
  853.              */
  854.             if (recov_start_msf.min > slioc_sav_end_msf.min)
  855.                 done = TRUE;
  856.             else if (recov_start_msf.min ==
  857.                  slioc_sav_end_msf.min) {
  858.                 if (recov_start_msf.sec >
  859.                     slioc_sav_end_msf.sec)
  860.                     done = TRUE;
  861.                 else if ((recov_start_msf.sec ==
  862.                       slioc_sav_end_msf.sec) &&
  863.                      (recov_start_msf.frame >
  864.                       slioc_sav_end_msf.frame)) {
  865.                     done = TRUE;
  866.                 }
  867.             }
  868.         }
  869.         else {
  870.             recov_start_msf.min = 0;
  871.             recov_start_msf.sec = 0;
  872.             recov_start_msf.frame = 0;
  873.         }
  874.  
  875.         if (!done && (slioc_sav_end_fmt & ADDR_BLK)) {
  876.             recov_start_addr = s->cur_tot_addr + ERR_SKIPBLKS;
  877.  
  878.             /* Check to see if we have skipped past
  879.              * the end.
  880.              */
  881.             if (recov_start_addr >= slioc_sav_end_addr)
  882.                 done = TRUE;
  883.         }
  884.         else
  885.             recov_start_addr = 0;
  886.  
  887.  
  888.         /* Restart playback */
  889.         if (!done) {
  890.             fprintf(errfp, "CD audio: %s\n",
  891.                 app_data.str_recoverr);
  892.  
  893.             slioc_do_playaudio(
  894.                 slioc_sav_end_fmt,
  895.                 recov_start_addr, slioc_sav_end_addr,
  896.                 &recov_start_msf, &slioc_sav_end_msf,
  897.                 0, 0
  898.             );
  899.  
  900.             in_slioc_get_playstatus = FALSE;
  901.             return TRUE;
  902.         }
  903.  
  904.         /*FALLTHROUGH*/
  905.     case CDROM_AUDIO_COMPLETED:
  906.     case CDROM_AUDIO_NO_STATUS:
  907.     case CDROM_AUDIO_INVALID:
  908.         done = TRUE;
  909.  
  910.         if (!slioc_fake_stop)
  911.             slioc_playing = FALSE;
  912.  
  913.         slioc_fake_stop = FALSE;
  914.  
  915.         switch (s->mode) {
  916.         case M_SAMPLE:
  917.             done = !slioc_run_sample(s);
  918.             break;
  919.  
  920.         case M_AB:
  921.             done = !slioc_run_ab(s);
  922.             break;
  923.  
  924.         case M_PLAY:
  925.         case M_PAUSE:
  926.             s->cur_trk_addr = 0;
  927.             s->cur_trk_min = s->cur_trk_sec = s->cur_trk_frame = 0;
  928.  
  929.             if (s->shuffle || s->program)
  930.                 done = !slioc_run_prog(s);
  931.  
  932.             if (s->repeat)
  933.                 done = !slioc_run_repeat(s);
  934.  
  935.             break;
  936.         }
  937.  
  938.         break;
  939.  
  940.     default:
  941.         /* Something is wrong with the data. */
  942.         done = FALSE;
  943.     }
  944.  
  945.     if (done) {
  946.         /* Reset states */
  947.         reset_curstat(s, FALSE);
  948.         s->mode = M_STOP;
  949.         slioc_sav_end_addr = 0;
  950.         slioc_sav_end_msf.min = slioc_sav_end_msf.sec =
  951.             slioc_sav_end_msf.frame = 0;
  952.         slioc_sav_end_fmt = 0;
  953.         errcnt = 0;
  954.         errblk = 0;
  955.         dpy_all(s);
  956.  
  957.         if (app_data.done_eject) {
  958.             /* Eject the disc */
  959.             slioc_load_eject(s);
  960.         }
  961.         else {
  962.             /* Spin down the disc */
  963.             slioc_start_stop(FALSE, FALSE);
  964.         }
  965.  
  966.         in_slioc_get_playstatus = FALSE;
  967.         return FALSE;
  968.     }
  969.  
  970.     in_slioc_get_playstatus = FALSE;
  971.     return TRUE;
  972. }
  973.  
  974.  
  975. /*
  976.  * slioc_cfg_vol
  977.  *    Audio volume control function
  978.  *
  979.  * Args:
  980.  *    vol - Logical volume value to set to
  981.  *    s - Pointer to the curstat_t structure
  982.  *    query - If TRUE, query current volume only
  983.  *    warp - Whether to set the volume and balance control slider
  984.  *        thumbs to the appropriate position.
  985.  *        Bits: WARP_VOL WARP_BAL
  986.  *
  987.  * Return:
  988.  *    The current logical volume value, or -1 on failure.
  989.  */
  990. STATIC int
  991. slioc_cfg_vol(int vol, curstat_t *s, bool_t query, byte_t warp)
  992. {
  993.     struct cdrom_volctrl    volctrl;
  994.     static bool_t        first = TRUE;
  995.  
  996.     memset((byte_t *) &volctrl, 0, sizeof(volctrl));
  997.  
  998.     if (query) {
  999.         if (first) {
  1000.             first = FALSE;
  1001.  
  1002.             /* SunOS/Linux doesn't give a way to read volume
  1003.              * setting via CDROM ioctl.
  1004.              * Force the setting to maximum.
  1005.              */
  1006.             vol = 100;
  1007.             s->level_left = s->level_right = 100;
  1008.  
  1009.             if (warp & WARP_VOL)
  1010.                 set_vol_slider(vol);
  1011.  
  1012.             if (warp & WARP_BAL)
  1013.                 set_bal_slider(0);
  1014.  
  1015.             (void) slioc_cfg_vol(vol, s, FALSE, FALSE);
  1016.         }
  1017.         return (vol);
  1018.     }
  1019.     else {
  1020.                 volctrl.channel0 = scale_vol(
  1021.             taper_vol(vol * (int) s->level_left / 100)
  1022.         );
  1023.                 volctrl.channel1 = scale_vol(
  1024.             taper_vol(vol * (int) s->level_right / 100)
  1025.         );
  1026.  
  1027.         DBGDUMP("cdrom_volctrl data bytes", (byte_t *) &volctrl,
  1028.             sizeof(struct cdrom_volctrl));
  1029.  
  1030.                 if (slioc_send(CDROMVOLCTRL, &volctrl, TRUE))
  1031.                         return (vol);
  1032.         else if (volctrl.channel0 != volctrl.channel1) {
  1033.             /* Set the balance to the center
  1034.              * and retry.
  1035.              */
  1036.             volctrl.channel0 = volctrl.channel1 =
  1037.                 scale_vol(taper_vol(vol));
  1038.  
  1039.             DBGDUMP("cdrom_volctrl data bytes",
  1040.                 (byte_t *) &volctrl,
  1041.                 sizeof(struct cdrom_volctrl));
  1042.  
  1043.             if (slioc_send(CDROMVOLCTRL, &volctrl, TRUE)) {
  1044.                 /* Success: Warp balance control */
  1045.                 s->level_left = s->level_right = 100;
  1046.                 set_bal_slider(0);
  1047.  
  1048.                 return (vol);
  1049.             }
  1050.  
  1051.             /* Still failed: just drop through */
  1052.         }
  1053.     }
  1054.  
  1055.     return -1;
  1056. }
  1057.  
  1058.  
  1059. /*
  1060.  * slioc_vendor_model
  1061.  *    Query and update CD-ROM vendor/model/revision information
  1062.  *
  1063.  * Args:
  1064.  *    s - Pointer to the curstat_t structure
  1065.  *
  1066.  * Return:
  1067.  *    Nothing.
  1068.  */
  1069. STATIC void
  1070. slioc_vendor_model(curstat_t *s)
  1071. {
  1072.     /*
  1073.      * There is currently no way to get this info,
  1074.      * so just fill in some default info.
  1075.      */
  1076.     strcpy(s->vendor, "standard");
  1077.     strcpy(s->prod, "CD-ROM drive    ");
  1078.     strcpy(s->revnum, " -- ");
  1079. }
  1080.  
  1081.  
  1082. /*
  1083.  * slioc_get_toc
  1084.  *    Query and update the CD Table Of Contents
  1085.  *
  1086.  * Args:
  1087.  *    s - Pointer to the curstat_t structure
  1088.  *
  1089.  * Return:
  1090.  *    TRUE - success
  1091.  *    FALSE - failure
  1092.  */
  1093. STATIC bool_t
  1094. slioc_get_toc(curstat_t *s)
  1095. {
  1096.     int            i;
  1097.     bool_t            ret = FALSE;
  1098.     struct cdrom_tochdr    h;
  1099.     struct cdrom_tocentry    *e,
  1100.                 *p;
  1101.  
  1102.     if (!slioc_rdtoc(&h, &e, 0))
  1103.         return FALSE;
  1104.  
  1105.     /* Fill curstat structure with TOC data */
  1106.     s->first_trk = h.cdth_trk0;
  1107.     s->last_trk = h.cdth_trk1;
  1108.  
  1109.     p = e;
  1110.  
  1111.     for (i = 0; i < (int) (h.cdth_trk1 - h.cdth_trk0 + 1); i++) {
  1112.         s->trkinfo[i].trkno = p->cdte_track;
  1113.         s->trkinfo[i].type = TYP_AUDIO;
  1114.  
  1115.         s->trkinfo[i].min = p->cdte_addr.msf.minute;
  1116.         s->trkinfo[i].sec = p->cdte_addr.msf.second;
  1117.         s->trkinfo[i].frame = p->cdte_addr.msf.frame;
  1118.         msftoblk(
  1119.             s->trkinfo[i].min,
  1120.             s->trkinfo[i].sec,
  1121.             s->trkinfo[i].frame,
  1122.             &s->trkinfo[i].addr,
  1123.             MSF_OFFSET(s)
  1124.         );
  1125.  
  1126.         if (p->cdte_track == CDROM_LEADOUT ||
  1127.             s->trkinfo[i].trkno == s->last_trk ||
  1128.             i == (MAXTRACK - 1)) {
  1129.             s->tot_min = s->trkinfo[i].min;
  1130.             s->tot_sec = s->trkinfo[i].sec;
  1131.             s->tot_frame = s->trkinfo[i].frame;
  1132.             s->tot_trks = i;
  1133.             s->tot_addr = s->trkinfo[i].addr;
  1134.  
  1135.             break;
  1136.         }
  1137.  
  1138.         p++;
  1139.     }
  1140.  
  1141.         free(e);
  1142.     return TRUE;
  1143. }
  1144.  
  1145.  
  1146. /*
  1147.  * slioc_start_stat_poll
  1148.  *    Start polling the drive for current playback status
  1149.  *
  1150.  * Args:
  1151.  *    s - Pointer to the curstat_t structure
  1152.  *
  1153.  * Return:
  1154.  *    Nothing.
  1155.  */
  1156. STATIC void
  1157. slioc_start_stat_poll(curstat_t *s)
  1158. {
  1159.     slioc_stat_polling = TRUE;
  1160.  
  1161.     /* Start poll timer */
  1162.     slioc_stat_id = cd_timeout(
  1163.         slioc_stat_interval,
  1164.         slioc_stat_poll,
  1165.         (byte_t *) s
  1166.     );
  1167. }
  1168.  
  1169.  
  1170. /*
  1171.  * slioc_stop_stat_poll
  1172.  *    Stop polling the drive for current playback status
  1173.  *
  1174.  * Args:
  1175.  *    Nothing.
  1176.  *
  1177.  * Return:
  1178.  *    Nothing.
  1179.  */
  1180. STATIC void
  1181. slioc_stop_stat_poll(void)
  1182. {
  1183.     if (slioc_stat_polling) {
  1184.         /* Stop poll timer */
  1185.         cd_untimeout(slioc_stat_id);
  1186.  
  1187.         slioc_stat_polling = FALSE;
  1188.     }
  1189. }
  1190.  
  1191.  
  1192. /*
  1193.  * slioc_start_insert_poll
  1194.  *    Start polling the drive for disc insertion
  1195.  *
  1196.  * Args:
  1197.  *    s - Pointer to the curstat_t structure
  1198.  *
  1199.  * Return:
  1200.  *    Nothing.
  1201.  */
  1202. STATIC void
  1203. slioc_start_insert_poll(curstat_t *s)
  1204. {
  1205.     if (slioc_insert_polling || s->mode != M_NODISC)
  1206.         return;
  1207.  
  1208.     slioc_insert_polling = TRUE;
  1209.  
  1210.     /* Start poll timer */
  1211.     slioc_insert_id = cd_timeout(
  1212.         app_data.ins_interval,
  1213.         slioc_insert_poll,
  1214.         (byte_t *) s
  1215.     );
  1216. }
  1217.  
  1218.  
  1219. /*
  1220.  * slioc_stop_insert_poll
  1221.  *    Stop polling the drive for disc insertion
  1222.  *
  1223.  * Args:
  1224.  *    s - Pointer to the curstat_t structure
  1225.  *
  1226.  * Return:
  1227.  *    Nothing.
  1228.  */
  1229. STATIC void
  1230. slioc_stop_insert_poll(void)
  1231. {
  1232.     if (slioc_insert_polling) {
  1233.         /* Stop poll timer */
  1234.         cd_untimeout(slioc_insert_id);
  1235.  
  1236.         slioc_insert_polling = FALSE;
  1237.     }
  1238. }
  1239.  
  1240.  
  1241. /*
  1242.  * slioc_stat_poll
  1243.  *    The playback status polling function
  1244.  *
  1245.  * Args:
  1246.  *    s - Pointer to the curstat_t structure
  1247.  *
  1248.  * Return:
  1249.  *    Nothing.
  1250.  */
  1251. STATIC void
  1252. slioc_stat_poll(curstat_t *s)
  1253. {
  1254.     if (!slioc_stat_polling)
  1255.         return;
  1256.  
  1257.     /* Get current audio playback status */
  1258.     if (slioc_get_playstatus(s)) {
  1259.         /* Register next poll interval */
  1260.         slioc_stat_id = cd_timeout(
  1261.             slioc_stat_interval,
  1262.             slioc_stat_poll,
  1263.             (byte_t *) s
  1264.         );
  1265.     }
  1266.     else
  1267.         slioc_stat_polling = FALSE;
  1268. }
  1269.  
  1270.  
  1271. /*
  1272.  * slioc_insert_poll
  1273.  *    The disc insertion polling function
  1274.  *
  1275.  * Args:
  1276.  *    s - Pointer to the curstat_t structure
  1277.  *
  1278.  * Return:
  1279.  *    Nothing.
  1280.  */
  1281. STATIC void
  1282. slioc_insert_poll(curstat_t *s)
  1283. {
  1284.     /* Check to see if a disc is inserted */
  1285.     if (!slioc_disc_ready(s)) {
  1286.         /* Register next poll interval */
  1287.         slioc_insert_id = cd_timeout(
  1288.             app_data.ins_interval,
  1289.             slioc_insert_poll,
  1290.             (byte_t *) s
  1291.         );
  1292.     }
  1293.     else
  1294.         slioc_insert_polling = FALSE;
  1295. }
  1296.  
  1297.  
  1298. /*
  1299.  * slioc_disc_ready
  1300.  *    Check if the disc is loaded and ready for use, and update
  1301.  *    curstat table.
  1302.  *
  1303.  * Args:
  1304.  *    s - Pointer to the curstat_t structure
  1305.  *
  1306.  * Return:
  1307.  *    TRUE - Disc is ready
  1308.  *    FALSE - Disc is not ready
  1309.  */
  1310. STATIC bool_t
  1311. slioc_disc_ready(curstat_t *s)
  1312. {
  1313.     int        i,
  1314.             vol;
  1315.     bool_t        err,
  1316.             first_open = FALSE;
  1317.     static bool_t    opened_once = FALSE;
  1318.  
  1319.     /* If device has not been opened, attempt to open it */
  1320.     if (slioc_not_open) {
  1321.         /* Check for another copy of the CD player running on
  1322.          * the specified device.
  1323.          */
  1324.         if (!cd_devlock(app_data.device)) {
  1325.             dpy_time(s, FALSE);
  1326.             slioc_start_insert_poll(s);
  1327.             return FALSE;
  1328.         }
  1329.  
  1330.         /* Open CD-ROM device */
  1331.         if (!slioc_open(app_data.device)) {
  1332.             dpy_time(s, FALSE);
  1333.             slioc_start_insert_poll(s);
  1334.             return FALSE;
  1335.         }
  1336.  
  1337.         if (!opened_once)
  1338.             first_open = TRUE;
  1339.  
  1340.         slioc_not_open = FALSE;
  1341.         opened_once = TRUE;
  1342.     }
  1343.  
  1344.     for (i = 0; i < 5; i++) {
  1345.         /* Check if a CD is loaded */
  1346.         if ((err = !slioc_disc_present(first_open)) == TRUE) {
  1347.             s->mode = M_NODISC;
  1348.             dbprog_dbclear(s);
  1349.         }
  1350.         else
  1351.             break;
  1352.     }
  1353.  
  1354.     if (!err && first_open) {
  1355.         /* Fill in inquiry data */
  1356.         slioc_vendor_model(s);
  1357.  
  1358.         /* Query current volume and warp volume and balance
  1359.          * sliders to appropriate setting
  1360.          */
  1361.         if ((vol = slioc_cfg_vol(0, s, TRUE, WARP_VOL | WARP_BAL)) >= 0)
  1362.             s->level = (byte_t) vol;
  1363.         else
  1364.             s->level = 0;
  1365.     }
  1366.  
  1367.     /* Read disc table of contents */
  1368.     if (err || (s->mode == M_NODISC && !slioc_get_toc(s))) {
  1369.         reset_curstat(s, TRUE);
  1370.         dpy_all(s);
  1371.  
  1372.         if (app_data.eject_close) {
  1373.             /* Close device */
  1374.             slioc_close();
  1375.  
  1376.             slioc_not_open = TRUE;
  1377.         }
  1378.  
  1379.         slioc_start_insert_poll(s);
  1380.         return FALSE;
  1381.     }
  1382.  
  1383.     if (s->mode == M_NODISC) {
  1384.         /* Load CD database entry for this disc */
  1385.         dbprog_dbget(s);
  1386.  
  1387.         s->mode = M_STOP;
  1388.         dpy_all(s);
  1389.  
  1390.         if (app_data.load_play) {
  1391.             /* Start auto-play */
  1392.             slioc_play_pause(s);
  1393.         }
  1394.         else if (app_data.load_spindown) {
  1395.             /* Spin down disc in case the user isn't going to
  1396.              * play anything for a while.  This reduces wear and
  1397.              * tear on the drive.
  1398.              */
  1399.             slioc_start_stop(FALSE, FALSE);
  1400.         }
  1401.         else {
  1402.             switch (slioc_tst_status) {
  1403.             case M_PLAY:
  1404.             case M_PAUSE:
  1405.                 /* Drive is current playing audio or paused:
  1406.                  * act appropriately.
  1407.                  */
  1408.                 s->mode = slioc_tst_status;
  1409.                 slioc_get_playstatus(s);
  1410.                 dpy_all(s);
  1411.                 if (s->mode == M_PAUSE)
  1412.                     cd_pause_blink(s, TRUE);
  1413.                 else
  1414.                     slioc_start_stat_poll(s);
  1415.                 break;
  1416.             default:
  1417.                 /* Drive is stopped: do nothing */
  1418.                 break;
  1419.             }
  1420.         }
  1421.     }
  1422.  
  1423.     return TRUE;
  1424. }
  1425.  
  1426.  
  1427. /*
  1428.  * slioc_run_rew
  1429.  *    Run search-rewind operation
  1430.  *
  1431.  * Args:
  1432.  *    s - Pointer to the curstat_t structure
  1433.  *
  1434.  * Return:
  1435.  *    Nothing.
  1436.  */
  1437. STATIC void
  1438. slioc_run_rew(curstat_t *s)
  1439. {
  1440.     int        i,
  1441.             skip_blks;
  1442.     word32_t    addr,
  1443.             end_addr;
  1444.     msf_t        smsf,
  1445.             emsf;
  1446.     static word32_t    start_addr,
  1447.             seq;
  1448.  
  1449.     /* Find out where we are */
  1450.     if (!slioc_get_playstatus(s)) {
  1451.         cd_beep();
  1452.         return;
  1453.     }
  1454.  
  1455.     skip_blks = app_data.skip_blks;
  1456.     addr = s->cur_tot_addr;
  1457.  
  1458.     if (slioc_start_search) {
  1459.         slioc_start_search = FALSE;
  1460.         seq = 0;
  1461.         if (skip_blks < addr)
  1462.             start_addr = addr - skip_blks;
  1463.         else
  1464.             start_addr = 0;
  1465.     }
  1466.     else {
  1467.         if (app_data.skip_spdup > 0 && seq > app_data.skip_spdup)
  1468.             /* Speed up search */
  1469.             skip_blks *= 3;
  1470.  
  1471.         if ((int) (start_addr - skip_blks) > 0)
  1472.             start_addr -= skip_blks;
  1473.         else
  1474.             start_addr = 0;
  1475.     }
  1476.  
  1477.     seq++;
  1478.  
  1479.     if (s->shuffle || s->program) {
  1480.         if ((i = curtrk_pos(s)) < 0)
  1481.             i = 0;
  1482.     }
  1483.     else
  1484.         i = 0;
  1485.  
  1486.     if (start_addr < s->trkinfo[i].addr)
  1487.         start_addr = s->trkinfo[i].addr;
  1488.  
  1489.     end_addr = start_addr + MAX_SRCH_BLKS;
  1490.  
  1491.     blktomsf(start_addr, &smsf.min, &smsf.sec, &smsf.frame, MSF_OFFSET(s));
  1492.     blktomsf(end_addr, &emsf.min, &emsf.sec, &emsf.frame, MSF_OFFSET(s));
  1493.  
  1494.     /* Play next search interval */
  1495.     slioc_do_playaudio(
  1496.         ADDR_BLK | ADDR_MSF | ADDR_OPTEND,
  1497.         start_addr, end_addr,
  1498.         &smsf, &emsf,
  1499.         0, 0
  1500.     );
  1501.  
  1502.     slioc_search_id = cd_timeout(
  1503.         app_data.skip_pause,
  1504.         slioc_run_rew,
  1505.         (byte_t *) s
  1506.     );
  1507. }
  1508.  
  1509.  
  1510. /*
  1511.  * slioc_stop_rew
  1512.  *    Stop search-rewind operation
  1513.  *
  1514.  * Args:
  1515.  *    s - Pointer to the curstat_t structure
  1516.  *
  1517.  * Return:
  1518.  *    Nothing.
  1519.  */
  1520. /*ARGSUSED*/
  1521. STATIC void
  1522. slioc_stop_rew(curstat_t *s)
  1523. {
  1524.     cd_untimeout(slioc_search_id);
  1525. }
  1526.  
  1527.  
  1528. /*
  1529.  * slioc_run_ff
  1530.  *    Run search-fast-forward operation
  1531.  *
  1532.  * Args:
  1533.  *    s - Pointer to the curstat_t structure
  1534.  *
  1535.  * Return:
  1536.  *    Nothing.
  1537.  */
  1538. STATIC void
  1539. slioc_run_ff(curstat_t *s)
  1540. {
  1541.     int        i,
  1542.             skip_blks;
  1543.     word32_t    addr,
  1544.             end_addr;
  1545.     msf_t        smsf,
  1546.             emsf;
  1547.     static word32_t    start_addr,
  1548.             seq;
  1549.  
  1550.     /* Find out where we are */
  1551.     if (!slioc_get_playstatus(s)) {
  1552.         cd_beep();
  1553.         return;
  1554.     }
  1555.  
  1556.     skip_blks = app_data.skip_blks;
  1557.     addr = s->cur_tot_addr;
  1558.  
  1559.     if (slioc_start_search) {
  1560.         slioc_start_search = FALSE;
  1561.         seq = 0;
  1562.         start_addr = addr + skip_blks;
  1563.     }
  1564.     else {
  1565.         if (app_data.skip_spdup > 0 && seq > app_data.skip_spdup)
  1566.             /* Speed up search */
  1567.             skip_blks *= 3;
  1568.  
  1569.         start_addr += skip_blks;
  1570.     }
  1571.  
  1572.     seq++;
  1573.  
  1574.     if (s->shuffle || s->program) {
  1575.         if ((i = curtrk_pos(s)) < 0)
  1576.             i = s->tot_trks - 1;
  1577.         else if (s->cur_idx == 0)
  1578.             /* We're in the lead-in: consider this to be
  1579.              * within the previous track.
  1580.              */
  1581.             i--;
  1582.     }
  1583.     else
  1584.         i = s->tot_trks - 1;
  1585.  
  1586.     end_addr = start_addr + MAX_SRCH_BLKS;
  1587.  
  1588.     if (end_addr >= s->trkinfo[i+1].addr) {
  1589.         end_addr = s->trkinfo[i+1].addr;
  1590.         start_addr = end_addr - skip_blks;
  1591.     }
  1592.  
  1593.     blktomsf(start_addr, &smsf.min, &smsf.sec, &smsf.frame, MSF_OFFSET(s));
  1594.     blktomsf(end_addr, &emsf.min, &emsf.sec, &emsf.frame, MSF_OFFSET(s));
  1595.  
  1596.     /* Play next search interval */
  1597.     slioc_do_playaudio(
  1598.         ADDR_BLK | ADDR_MSF | ADDR_OPTEND,
  1599.         start_addr, end_addr,
  1600.         &smsf, &emsf,
  1601.         0, 0
  1602.     );
  1603.  
  1604.     slioc_search_id = cd_timeout(
  1605.         app_data.skip_pause,
  1606.         slioc_run_ff,
  1607.         (byte_t *) s
  1608.     );
  1609. }
  1610.  
  1611.  
  1612. /*
  1613.  * slioc_stop_ff
  1614.  *    Stop search-fast-forward operation
  1615.  *
  1616.  * Args:
  1617.  *    s - Pointer to the curstat_t structure
  1618.  *
  1619.  * Return:
  1620.  *    Nothing.
  1621.  */
  1622. /*ARGSUSED*/
  1623. STATIC void
  1624. slioc_stop_ff(curstat_t *s)
  1625. {
  1626.     cd_untimeout(slioc_search_id);
  1627. }
  1628.  
  1629.  
  1630. /*
  1631.  * slioc_run_ab
  1632.  *    Run a->b segment play operation
  1633.  *
  1634.  * Args:
  1635.  *    s - Pointer to the curstat_t structure
  1636.  *
  1637.  * Return:
  1638.  *    TRUE - success
  1639.  *    FALSE - failure
  1640.  */
  1641. /*ARGSUSED*/
  1642. STATIC bool_t
  1643. slioc_run_ab(curstat_t *s)
  1644. {
  1645.     return (
  1646.         slioc_do_playaudio(
  1647.             ADDR_BLK | ADDR_MSF,
  1648.             slioc_ab_start_addr, slioc_ab_end_addr,
  1649.             &slioc_ab_start_msf, &slioc_ab_end_msf,
  1650.             0, 0
  1651.         )
  1652.     );
  1653. }
  1654.  
  1655.  
  1656. /*
  1657.  * slioc_run_sample
  1658.  *    Run sample play operation
  1659.  *
  1660.  * Args:
  1661.  *    s - Pointer to the curstat_t structure
  1662.  *
  1663.  * Return:
  1664.  *    TRUE - success
  1665.  *    FALSE - failure
  1666.  */
  1667. STATIC bool_t
  1668. slioc_run_sample(curstat_t *s)
  1669. {
  1670.     word32_t    saddr,
  1671.             eaddr;
  1672.     msf_t        smsf,
  1673.             emsf;
  1674.  
  1675.     if (slioc_next_sam < s->tot_trks) {
  1676.         saddr = s->trkinfo[slioc_next_sam].addr;
  1677.         eaddr = saddr + app_data.sample_blks,
  1678.  
  1679.         blktomsf(
  1680.             saddr,
  1681.             &smsf.min,
  1682.             &smsf.sec,
  1683.             &smsf.frame,
  1684.             MSF_OFFSET(s)
  1685.         );
  1686.         blktomsf(
  1687.             eaddr,
  1688.             &emsf.min,
  1689.             &emsf.sec,
  1690.             &emsf.frame,
  1691.             MSF_OFFSET(s)
  1692.         );
  1693.  
  1694.         if (slioc_do_playaudio(ADDR_BLK | ADDR_MSF,
  1695.                  saddr, eaddr, &smsf, &emsf, 0, 0)) {
  1696.             slioc_next_sam++;
  1697.             return TRUE;
  1698.         }
  1699.     }
  1700.  
  1701.     slioc_next_sam = 0;
  1702.     return FALSE;
  1703. }
  1704.  
  1705.  
  1706. /*
  1707.  * slioc_run_prog
  1708.  *    Run program/shuffle play operation
  1709.  *
  1710.  * Args:
  1711.  *    s - Pointer to the curstat_t structure
  1712.  *
  1713.  * Return:
  1714.  *    TRUE - success
  1715.  *    FALSE - failure
  1716.  */
  1717. STATIC bool_t
  1718. slioc_run_prog(curstat_t *s)
  1719. {
  1720.     sword32_t    i;
  1721.     word32_t    start_addr,
  1722.             end_addr;
  1723.     msf_t        start_msf,
  1724.             end_msf;
  1725.     bool_t        ret;
  1726.  
  1727.     if (!s->shuffle && s->prog_tot <= 0)
  1728.         return FALSE;
  1729.  
  1730.     if (slioc_new_progshuf) {
  1731.         if (s->shuffle)
  1732.             /* New shuffle sequence needed */
  1733.             reset_shuffle(s);
  1734.         else
  1735.             /* Program play: simply reset the count */
  1736.             s->prog_cnt = 0;
  1737.  
  1738.         slioc_new_progshuf = FALSE;
  1739.     }
  1740.  
  1741.     if (s->prog_cnt >= s->prog_tot)
  1742.         /* Done with program/shuffle play cycle */
  1743.         return FALSE;
  1744.  
  1745.     if ((i = curprog_pos(s)) < 0)
  1746.         return FALSE;
  1747.  
  1748.     if (s->trkinfo[i].trkno == CDROM_LEADOUT)
  1749.         return FALSE;
  1750.  
  1751.     s->prog_cnt++;
  1752.     s->cur_trk = s->trkinfo[i].trkno;
  1753.     s->cur_idx = 1;
  1754.  
  1755.     start_addr = s->trkinfo[i].addr + s->cur_trk_addr;
  1756.     blktomsf(
  1757.         start_addr,
  1758.         &s->cur_tot_min,
  1759.         &s->cur_tot_sec,
  1760.         &s->cur_tot_frame,
  1761.         MSF_OFFSET(s)
  1762.     );
  1763.     start_msf.min = s->cur_tot_min;
  1764.     start_msf.sec = s->cur_tot_sec;
  1765.     start_msf.frame = s->cur_tot_frame;
  1766.  
  1767.     end_addr = s->trkinfo[i+1].addr;
  1768.     end_msf.min = s->trkinfo[i+1].min;
  1769.     end_msf.sec = s->trkinfo[i+1].sec;
  1770.     end_msf.frame = s->trkinfo[i+1].frame;
  1771.  
  1772.     s->cur_tot_addr = start_addr;
  1773.  
  1774.     if (s->mode != M_PAUSE)
  1775.         s->mode = M_PLAY;
  1776.  
  1777.     dpy_all(s);
  1778.  
  1779.     if (s->trkinfo[i].type == TYP_DATA)
  1780.         /* Data track: just fake it */
  1781.         return TRUE;
  1782.  
  1783.     ret = slioc_do_playaudio(
  1784.         ADDR_BLK | ADDR_MSF,
  1785.         start_addr, end_addr,
  1786.         &start_msf, &end_msf,
  1787.         0, 0
  1788.     );
  1789.  
  1790.     if (s->mode == M_PAUSE) {
  1791.         slioc_pause_resume(FALSE);
  1792.  
  1793.         /* Restore volume */
  1794.         slioc_mute_off(s);
  1795.     }
  1796.  
  1797.     return (ret);
  1798. }
  1799.  
  1800.  
  1801. /*
  1802.  * slioc_run_repeat
  1803.  *    Run repeat play operation
  1804.  *
  1805.  * Args:
  1806.  *    s - Pointer to the curstat_t structure
  1807.  *
  1808.  * Return:
  1809.  *    TRUE - success
  1810.  *    FALSE - failure
  1811.  */
  1812. STATIC bool_t
  1813. slioc_run_repeat(curstat_t *s)
  1814. {
  1815.     msf_t    start_msf,
  1816.         end_msf;
  1817.     int    ret;
  1818.  
  1819.     if (!s->repeat)
  1820.         return FALSE;
  1821.  
  1822.     if (s->prog_tot > 0) {
  1823.         ret = TRUE;
  1824.  
  1825.         if (s->prog_cnt < s->prog_tot)
  1826.             /* Not done with program/shuffle sequence yet */
  1827.             return (ret);
  1828.  
  1829.         slioc_new_progshuf = TRUE;
  1830.         s->rptcnt++;
  1831.     }
  1832.     else {
  1833.         s->cur_trk = s->first_trk;
  1834.         s->cur_idx = 1;
  1835.  
  1836.         s->cur_tot_addr = 0;
  1837.         s->cur_tot_min = 0;
  1838.         s->cur_tot_sec = 0;
  1839.         s->cur_tot_frame = 0;
  1840.         s->rptcnt++;
  1841.         dpy_all(s);
  1842.  
  1843.         start_msf.min = s->trkinfo[0].min;
  1844.         start_msf.sec = s->trkinfo[0].sec;
  1845.         start_msf.frame = s->trkinfo[0].frame;
  1846.         end_msf.min = s->tot_min;
  1847.         end_msf.sec = s->tot_sec;
  1848.         end_msf.frame = s->tot_frame;
  1849.  
  1850.         ret = slioc_do_playaudio(
  1851.             ADDR_BLK | ADDR_MSF,
  1852.             s->trkinfo[0].addr, s->tot_addr,
  1853.             &start_msf, &end_msf, 0, 0
  1854.         );
  1855.  
  1856.         if (s->mode == M_PAUSE) {
  1857.             slioc_pause_resume(FALSE);
  1858.  
  1859.             /* Restore volume */
  1860.             slioc_mute_off(s);
  1861.         }
  1862.  
  1863.     }
  1864.  
  1865.     return (ret);
  1866. }
  1867.  
  1868.  
  1869. /***********************
  1870.  *   public routines   *
  1871.  ***********************/
  1872.  
  1873.  
  1874. /*
  1875.  * slioc_init
  1876.  *    Top-level function to initialize the SunOS/Linux ioctl method.
  1877.  *
  1878.  * Args:
  1879.  *    s - Pointer to the curstat_t structure
  1880.  *
  1881.  * Return:
  1882.  *    Nothing.
  1883.  */
  1884. void
  1885. slioc_init(curstat_t *s, di_tbl_t *dt)
  1886. {
  1887.     int    i;
  1888.  
  1889.     if (app_data.di_method != DI_SLIOC)
  1890.         /* SunOS/Linux ioctl method not configured */
  1891.         return;
  1892.  
  1893.     /* Initialize libdi calling table */
  1894.     dt->check_disc = slioc_check_disc;
  1895.     dt->status_upd = slioc_status_upd;
  1896.     dt->lock = slioc_lock;
  1897.     dt->repeat = slioc_repeat;
  1898.     dt->shuffle = slioc_shuffle;
  1899.     dt->load_eject = slioc_load_eject;
  1900.     dt->ab = slioc_ab;
  1901.     dt->sample = slioc_sample;
  1902.     dt->level = slioc_level;
  1903.     dt->play_pause = slioc_play_pause;
  1904.     dt->stop = slioc_stop;
  1905.     dt->prevtrk = slioc_prevtrk;
  1906.     dt->nexttrk = slioc_nexttrk;
  1907.     dt->previdx = slioc_previdx;
  1908.     dt->nextidx = slioc_nextidx;
  1909.     dt->rew = slioc_rew;
  1910.     dt->ff = slioc_ff;
  1911.     dt->warp = slioc_warp;
  1912.     dt->route = NULL;
  1913.     dt->mute_on = slioc_mute_on;
  1914.     dt->mute_off = slioc_mute_off;
  1915.     dt->start = slioc_start;
  1916.     dt->icon = slioc_icon;
  1917.     dt->halt = slioc_halt;
  1918.     dt->mode = slioc_mode;
  1919.     dt->vers = slioc_vers;
  1920.  
  1921.     /* Hardwire some unsupported features */
  1922.     app_data.caddylock_supp = FALSE;
  1923.     app_data.caddy_lock = FALSE;
  1924.     app_data.chroute_supp = FALSE;
  1925.  
  1926.     /* Initalize SunOS/Linux ioctl method */
  1927.     slioc_stat_polling = FALSE;
  1928.     slioc_stat_interval = app_data.stat_interval;
  1929.     slioc_insert_polling = FALSE;
  1930.     slioc_next_sam = FALSE;
  1931.     slioc_new_progshuf = FALSE;
  1932.     slioc_sav_end_addr = 0;
  1933.     slioc_sav_end_msf.min = slioc_sav_end_msf.sec =
  1934.         slioc_sav_end_msf.frame = 0;
  1935.     slioc_sav_end_fmt = 0;
  1936.  
  1937.     /* Initialize curstat structure */
  1938.     reset_curstat(s, TRUE);
  1939. }
  1940.  
  1941.  
  1942. /*
  1943.  * slioc_check_disc
  1944.  *    Check if disc is ready for use
  1945.  *
  1946.  * Args:
  1947.  *    s - Pointer to the curstat_t structure
  1948.  *
  1949.  * Return:
  1950.  *    TRUE - success
  1951.  *    FALSE - failure
  1952.  */
  1953. bool_t
  1954. slioc_check_disc(curstat_t *s)
  1955. {
  1956.     return (slioc_disc_ready(s));
  1957. }
  1958.  
  1959.  
  1960. /*
  1961.  * slioc_status_upd
  1962.  *    Force update of playback status
  1963.  *
  1964.  * Args:
  1965.  *    s - Pointer to the curstat_t structure
  1966.  *
  1967.  * Return:
  1968.  *    Nothing.
  1969.  */
  1970. void
  1971. slioc_status_upd(curstat_t *s)
  1972. {
  1973.     slioc_get_playstatus(s);
  1974. }
  1975.  
  1976.  
  1977. /*
  1978.  * slioc_lock
  1979.  *    Caddy lock function
  1980.  *
  1981.  * Args:
  1982.  *    s - Pointer to the curstat_t structure
  1983.  *    enable - whether to enable/disable caddy lock
  1984.  *
  1985.  * Return:
  1986.  *    Nothing.
  1987.  */
  1988. void
  1989. slioc_lock(curstat_t *s, bool_t enable)
  1990. {
  1991.     /* Caddy lock function currently not supported
  1992.      * under SunOS/Linux ioctl method
  1993.      */
  1994.     if (enable) {
  1995.         cd_beep();
  1996.         set_lock_btn(FALSE);
  1997.     }
  1998. }
  1999.  
  2000.  
  2001. /*
  2002.  * slioc_repeat
  2003.  *    Repeat mode function
  2004.  *
  2005.  * Args:
  2006.  *    s - Pointer to the curstat_t structure
  2007.  *    enable - whether to enable/disable repeat mode
  2008.  *
  2009.  * Return:
  2010.  *    Nothing.
  2011.  */
  2012. void
  2013. slioc_repeat(curstat_t *s, bool_t enable)
  2014. {
  2015.     s->repeat = enable;
  2016.     dpy_rptcnt(s);
  2017. }
  2018.  
  2019.  
  2020. /*
  2021.  * slioc_shuffle
  2022.  *    Shuffle mode function
  2023.  *
  2024.  * Args:
  2025.  *    s - Pointer to the curstat_t structure
  2026.  *    enable - whether to enable/disable shuffle mode
  2027.  *
  2028.  * Return:
  2029.  *    Nothing.
  2030.  */
  2031. void
  2032. slioc_shuffle(curstat_t *s, bool_t enable)
  2033. {
  2034.     switch (s->mode) {
  2035.     case M_STOP:
  2036.     case M_NODISC:
  2037.         if (s->prog_tot > 0 && !s->shuffle) {
  2038.             /* Currently in program mode: can't enable shuffle */
  2039.             cd_beep();
  2040.             set_shuffle_btn((bool_t) !enable);
  2041.             return;
  2042.         }
  2043.         break;
  2044.     default:
  2045.         if (enable) {
  2046.             /* Can't enable shuffle unless when stopped */
  2047.             cd_beep();
  2048.             set_shuffle_btn((bool_t) !enable);
  2049.             return;
  2050.         }
  2051.         break;
  2052.     }
  2053.  
  2054.     s->shuffle = enable;
  2055.     if (!s->shuffle)
  2056.         s->prog_tot = 0;
  2057. }
  2058.  
  2059.  
  2060. /*
  2061.  * slioc_load_eject
  2062.  *    CD caddy load and eject function.  If disc caddy is not
  2063.  *    loaded, it will attempt to load it.  Otherwise, it will be
  2064.  *    ejected.
  2065.  *
  2066.  * Args:
  2067.  *    s - Pointer to the curstat_t structure
  2068.  *
  2069.  * Return:
  2070.  *    Nothing.
  2071.  */
  2072. void
  2073. slioc_load_eject(curstat_t *s)
  2074. {
  2075.     bool_t    ret = FALSE;
  2076.  
  2077.     if (!slioc_disc_ready(s)) {
  2078.         /* Disc not ready: try loading the disc */
  2079.         if (!slioc_start_stop(TRUE, TRUE))
  2080.             cd_beep();
  2081.  
  2082.         return;
  2083.     }
  2084.  
  2085.     /* Eject the disc */
  2086.  
  2087.     if (!app_data.eject_supp) {
  2088.         cd_beep();
  2089.  
  2090.         slioc_stop_stat_poll();
  2091.         reset_curstat(s, TRUE);
  2092.         s->mode = M_NODISC;
  2093.  
  2094.         dbprog_dbclear(s);
  2095.         dpy_all(s);
  2096.  
  2097.         if (app_data.eject_close) {
  2098.             /* Close device */
  2099.             slioc_close();
  2100.  
  2101.             slioc_not_open = TRUE;
  2102.         }
  2103.  
  2104.         slioc_start_insert_poll(s);
  2105.         return;
  2106.     }
  2107.  
  2108.     slioc_stop_stat_poll();
  2109.     reset_curstat(s, TRUE);
  2110.     s->mode = M_NODISC;
  2111.  
  2112.     dbprog_dbclear(s);
  2113.     dpy_all(s);
  2114.  
  2115.     slioc_start_stop(FALSE, TRUE);
  2116.  
  2117.     if (app_data.eject_exit)
  2118.         cd_quit(s);
  2119.     else {
  2120.         if (app_data.eject_close) {
  2121.             /* Close device */
  2122.             slioc_close();
  2123.  
  2124.             slioc_not_open = TRUE;
  2125.         }
  2126.             
  2127.         slioc_start_insert_poll(s);
  2128.     }
  2129. }
  2130.  
  2131.  
  2132. /*
  2133.  * slioc_ab
  2134.  *    A->B segment play mode function
  2135.  *
  2136.  * Args:
  2137.  *    s - Pointer to the curstat_t structure
  2138.  *
  2139.  * Return:
  2140.  *    Nothing.
  2141.  */
  2142. void
  2143. slioc_ab(curstat_t *s)
  2144. {
  2145.     switch (s->mode) {
  2146.     case M_SAMPLE:
  2147.     case M_PLAY:
  2148.         /* Get current location */
  2149.         if (!slioc_get_playstatus(s)) {
  2150.             cd_beep();
  2151.             break;
  2152.         }
  2153.  
  2154.         slioc_ab_start_addr = s->cur_tot_addr;
  2155.         slioc_ab_start_msf.min = s->cur_tot_min;
  2156.         slioc_ab_start_msf.sec = s->cur_tot_sec;
  2157.         slioc_ab_start_msf.frame = s->cur_tot_frame;
  2158.  
  2159.         s->mode = M_A;
  2160.         dpy_playmode(s, FALSE);
  2161.         break;
  2162.  
  2163.     case M_A:
  2164.         /* Get current location */
  2165.         if (!slioc_get_playstatus(s)) {
  2166.             cd_beep();
  2167.             break;
  2168.         }
  2169.  
  2170.         slioc_ab_end_addr = s->cur_tot_addr;
  2171.         slioc_ab_end_msf.min = s->cur_tot_min;
  2172.         slioc_ab_end_msf.sec = s->cur_tot_sec;
  2173.         slioc_ab_end_msf.frame = s->cur_tot_frame;
  2174.  
  2175.         /* Make sure that the A->B play interval is no less
  2176.          * than a user-configurable minimum.
  2177.          */
  2178.         if ((slioc_ab_end_addr - slioc_ab_start_addr) <
  2179.             app_data.min_playblks) {
  2180.             slioc_ab_end_addr = slioc_ab_start_addr +
  2181.                         app_data.min_playblks;
  2182.             blktomsf(
  2183.                 slioc_ab_end_addr,
  2184.                 &slioc_ab_end_msf.min,
  2185.                 &slioc_ab_end_msf.sec,
  2186.                 &slioc_ab_end_msf.frame,
  2187.                 MSF_OFFSET(s)
  2188.             );
  2189.         }
  2190.  
  2191.         if (!slioc_run_ab(s)) {
  2192.             cd_beep();
  2193.             return;
  2194.         }
  2195.  
  2196.         s->mode = M_AB;
  2197.         dpy_playmode(s, FALSE);
  2198.         break;
  2199.  
  2200.     case M_AB:
  2201.         /* Currently doing A->B playback, just call slioc_play_pause
  2202.          * to resume normal playback.
  2203.          */
  2204.         slioc_play_pause(s);
  2205.         break;
  2206.  
  2207.     default:
  2208.         cd_beep();
  2209.         break;
  2210.     }
  2211. }
  2212.  
  2213.  
  2214. /*
  2215.  * slioc_sample
  2216.  *    Sample play mode function
  2217.  *
  2218.  * Args:
  2219.  *    s - Pointer to the curstat_t structure
  2220.  *
  2221.  * Return:
  2222.  *    Nothing.
  2223.  */
  2224. void
  2225. slioc_sample(curstat_t *s)
  2226. {
  2227.     int    i;
  2228.  
  2229.     if (!slioc_disc_ready(s)) {
  2230.         cd_beep();
  2231.         return;
  2232.     }
  2233.  
  2234.     if (s->shuffle || s->prog_tot > 0) {
  2235.         /* Sample is not supported in program/shuffle mode */
  2236.         cd_beep();
  2237.         return;
  2238.     }
  2239.  
  2240.     switch (s->mode) {
  2241.     case M_STOP:
  2242.         slioc_start_stat_poll(s);
  2243.         /*FALLTHROUGH*/
  2244.     case M_A:
  2245.     case M_AB:
  2246.     case M_PLAY:
  2247.         /* If already playing a track, start sampling the track after
  2248.          * the current one.  Otherwise, sample from the beginning.
  2249.          */
  2250.         if (s->cur_trk > 0 && s->cur_trk != s->last_trk) {
  2251.             i = curtrk_pos(s) + 1;
  2252.             s->cur_trk = s->trkinfo[i].trkno;
  2253.             slioc_next_sam = i;
  2254.         }
  2255.         else {
  2256.             s->cur_trk = s->first_trk;
  2257.             slioc_next_sam = 0;
  2258.         }
  2259.         
  2260.         s->cur_idx = 1;
  2261.  
  2262.         s->mode = M_SAMPLE;
  2263.         dpy_all(s);
  2264.  
  2265.         if (!slioc_run_sample(s))
  2266.             return;
  2267.  
  2268.         break;
  2269.  
  2270.     case M_SAMPLE:
  2271.         /* Currently doing Sample playback, just call slioc_play_pause
  2272.          * to resume normal playback.
  2273.          */
  2274.         slioc_play_pause(s);
  2275.         break;
  2276.  
  2277.     default:
  2278.         cd_beep();
  2279.         break;
  2280.     }
  2281. }
  2282.  
  2283.  
  2284. /*
  2285.  * slioc_level
  2286.  *    Audio volume control function
  2287.  *
  2288.  * Args:
  2289.  *    s - Pointer to the curstat_t structure
  2290.  *    level - The volume level to set to
  2291.  *    drag - Whether this is an update due to the user dragging the
  2292.  *        volume control slider thumb.  If this is FALSE, then
  2293.  *        a final volume setting has been found.
  2294.  *
  2295.  * Return:
  2296.  *    Nothing.
  2297.  */
  2298. void
  2299. slioc_level(curstat_t *s, byte_t level, bool_t drag)
  2300. {
  2301.     int    actual;
  2302.     byte_t    warpflg;
  2303.  
  2304.     if (drag)
  2305.         warpflg = WARP_VOL;
  2306.     else
  2307.         warpflg = WARP_VOL | WARP_BAL;
  2308.  
  2309.     /* Set volume level */
  2310.     if ((actual = slioc_cfg_vol((int) level, s, FALSE, warpflg)) >= 0)
  2311.         s->level = (byte_t) actual;
  2312. }
  2313.  
  2314.  
  2315. /*
  2316.  * slioc_play_pause
  2317.  *    Audio playback and pause function
  2318.  *
  2319.  * Args:
  2320.  *    s - Pointer to the curstat_t structure
  2321.  *
  2322.  * Return:
  2323.  *    Nothing.
  2324.  */
  2325. void
  2326. slioc_play_pause(curstat_t *s)
  2327. {
  2328.     sword32_t    i;
  2329.     word32_t    start_addr;
  2330.     msf_t        start_msf,
  2331.             end_msf;
  2332.  
  2333.     if (!slioc_disc_ready(s)) {
  2334.         cd_beep();
  2335.         return;
  2336.     }
  2337.  
  2338.     if (s->mode == M_NODISC)
  2339.         s->mode = M_STOP;
  2340.  
  2341.     switch (s->mode) {
  2342.     case M_PLAY:
  2343.         /* Currently playing: go to pause mode */
  2344.  
  2345.         if (!slioc_pause_resume(FALSE)) {
  2346.             cd_beep();
  2347.             return;
  2348.         }
  2349.         slioc_stop_stat_poll();
  2350.         s->mode = M_PAUSE;
  2351.         dpy_playmode(s, FALSE);
  2352.         break;
  2353.  
  2354.     case M_PAUSE:
  2355.         /* Currently paused: resume play */
  2356.  
  2357.         if (!slioc_pause_resume(TRUE)) {
  2358.             cd_beep();
  2359.             return;
  2360.         }
  2361.         s->mode = M_PLAY;
  2362.         dpy_playmode(s, FALSE);
  2363.         slioc_start_stat_poll(s);
  2364.         break;
  2365.  
  2366.     case M_STOP:
  2367.         /* Currently stopped: start play */
  2368.  
  2369.         if (s->shuffle || s->prog_tot > 0) {
  2370.             slioc_new_progshuf = TRUE;
  2371.  
  2372.             /* Start shuffle/program play */
  2373.             if (!slioc_run_prog(s)) {
  2374.                 s->program = FALSE;
  2375.                 return;
  2376.             }
  2377.  
  2378.             s->program = !s->shuffle;
  2379.         }
  2380.         else {
  2381.             /* Start normal play */
  2382.             if ((i = curtrk_pos(s)) < 0 || s->cur_trk <= 0) {
  2383.                 /* Start play from the beginning */
  2384.                 i = 0;
  2385.                 s->cur_trk = s->first_trk;
  2386.                 start_addr = s->trkinfo[0].addr +
  2387.                          s->cur_trk_addr;
  2388.                 blktomsf(start_addr,
  2389.                      &start_msf.min,
  2390.                      &start_msf.sec,
  2391.                      &start_msf.frame,
  2392.                      MSF_OFFSET(s)
  2393.                 );
  2394.             }
  2395.             else {
  2396.                 /* User has specified a starting track */
  2397.                 start_addr = s->trkinfo[i].addr +
  2398.                          s->cur_trk_addr;
  2399.             }
  2400.  
  2401.             blktomsf(start_addr,
  2402.                  &start_msf.min,
  2403.                  &start_msf.sec,
  2404.                  &start_msf.frame,
  2405.                  MSF_OFFSET(s)
  2406.             );
  2407.  
  2408.             end_msf.min = s->tot_min;
  2409.             end_msf.sec = s->tot_sec;
  2410.             end_msf.frame = s->tot_frame;
  2411.  
  2412.             s->cur_idx = 1;
  2413.             s->mode = M_PLAY;
  2414.             if (s->trkinfo[i].type == TYP_DATA)
  2415.                 dpy_time(s, FALSE);
  2416.  
  2417.             if (!slioc_do_playaudio(ADDR_BLK | ADDR_MSF,
  2418.                       start_addr, s->tot_addr,
  2419.                       &start_msf, &end_msf, 0, 0)) {
  2420.                 cd_beep();
  2421.                 s->mode = M_STOP;
  2422.                 return;
  2423.             }
  2424.         }
  2425.  
  2426.         dpy_all(s);
  2427.         slioc_start_stat_poll(s);
  2428.         break;
  2429.  
  2430.     case M_A:
  2431.         /* Just reset mode to play and continue */
  2432.         s->mode = M_PLAY;
  2433.         dpy_playmode(s, FALSE);
  2434.         break;
  2435.  
  2436.     case M_AB:
  2437.     case M_SAMPLE:
  2438.         /* Force update of curstat */
  2439.         if (!slioc_get_playstatus(s)) {
  2440.             cd_beep();
  2441.             return;
  2442.         }
  2443.  
  2444.         /* Currently doing a->b or sample playback: just resume play */
  2445.         if (s->shuffle || s->program) {
  2446.             if ((i = curtrk_pos(s)) < 0 ||
  2447.                 s->trkinfo[i].trkno == CDROM_LEADOUT)
  2448.                 return;
  2449.  
  2450.             start_msf.min = s->cur_tot_min;
  2451.             start_msf.sec = s->cur_tot_sec;
  2452.             start_msf.frame = s->cur_tot_frame;
  2453.             end_msf.min = s->trkinfo[i+1].min;
  2454.             end_msf.sec = s->trkinfo[i+1].sec;
  2455.             end_msf.frame = s->trkinfo[i+1].frame;
  2456.  
  2457.             if (!slioc_do_playaudio(ADDR_BLK | ADDR_MSF,
  2458.                       s->cur_tot_addr,
  2459.                       s->trkinfo[i+1].addr,
  2460.                       &start_msf, &end_msf, 0, 0)) {
  2461.                 cd_beep();
  2462.                 return;
  2463.             }
  2464.         }
  2465.         else {
  2466.             start_msf.min = s->cur_tot_min;
  2467.             start_msf.sec = s->cur_tot_sec;
  2468.             start_msf.frame = s->cur_tot_frame;
  2469.             end_msf.min = s->tot_min;
  2470.             end_msf.sec = s->tot_sec;
  2471.             end_msf.frame = s->tot_frame;
  2472.  
  2473.             if (!slioc_do_playaudio(ADDR_BLK | ADDR_MSF,
  2474.                       s->cur_tot_addr, s->tot_addr,
  2475.                       &start_msf, &end_msf, 0, 0)) {
  2476.                 cd_beep();
  2477.                 return;
  2478.             }
  2479.         }
  2480.         s->mode = M_PLAY;
  2481.         dpy_playmode(s, FALSE);
  2482.         break;
  2483.  
  2484.     default:
  2485.         cd_beep();
  2486.         break;
  2487.     }
  2488. }
  2489.  
  2490.  
  2491. /*
  2492.  * slioc_stop
  2493.  *    Stop function
  2494.  *
  2495.  * Args:
  2496.  *    s - Pointer to the curstat_t structure
  2497.  *    stop_disc - Whether to actually spin down the disc or just
  2498.  *        update status.
  2499.  *
  2500.  * Return:
  2501.  *    Nothing.
  2502.  */
  2503. void
  2504. slioc_stop(curstat_t *s, bool_t stop_disc)
  2505. {
  2506.     /* The stop_disc parameter will cause the disc to spin down.
  2507.      * This is usually set to TRUE, but can be FALSE if the caller
  2508.      * just wants to set the current state to stop but will
  2509.      * immediately go into play state again.  Not spinning down
  2510.      * the drive makes things a little faster...
  2511.      */
  2512.  
  2513.     if (!slioc_disc_ready(s)) {
  2514.         cd_beep();
  2515.         return;
  2516.     }
  2517.  
  2518.     switch (s->mode) {
  2519.     case M_PLAY:
  2520.     case M_PAUSE:
  2521.     case M_A:
  2522.     case M_AB:
  2523.     case M_SAMPLE:
  2524.     case M_STOP:
  2525.         /* Currently playing or paused: stop */
  2526.  
  2527.         if (stop_disc && !slioc_start_stop(FALSE, FALSE)) {
  2528.             cd_beep();
  2529.             return;
  2530.         }
  2531.         slioc_stop_stat_poll();
  2532.  
  2533.         reset_curstat(s, FALSE);
  2534.         s->mode = M_STOP;
  2535.  
  2536.         dpy_all(s);
  2537.         break;
  2538.  
  2539.     default:
  2540.         cd_beep();
  2541.         break;
  2542.     }
  2543. }
  2544.  
  2545.  
  2546. /*
  2547.  * slioc_prevtrk
  2548.  *    Previous track function
  2549.  *
  2550.  * Args:
  2551.  *    s - Pointer to the curstat_t structure
  2552.  *
  2553.  * Return:
  2554.  *    Nothing.
  2555.  */
  2556. void
  2557. slioc_prevtrk(curstat_t *s)
  2558. {
  2559.     sword32_t    i;
  2560.     word32_t    start_addr;
  2561.     msf_t        start_msf,
  2562.             end_msf;
  2563.     bool_t        go_prev;
  2564.  
  2565.     if (!slioc_disc_ready(s)) {
  2566.         cd_beep();
  2567.         return;
  2568.     }
  2569.  
  2570.     switch (s->mode) {
  2571.     case M_A:
  2572.     case M_AB:
  2573.     case M_SAMPLE:
  2574.         s->mode = M_PLAY;
  2575.         dpy_playmode(s, FALSE);
  2576.         /*FALLTHROUGH*/
  2577.     case M_PLAY:
  2578.     case M_PAUSE:
  2579.         /* Find appropriate track to start */
  2580.         if (s->prog_tot > 0) {
  2581.             if (s->prog_cnt > 0) {
  2582.                 s->prog_cnt--;
  2583.                 slioc_new_progshuf = FALSE;
  2584.             }
  2585.             i = curprog_pos(s);
  2586.         }
  2587.         else
  2588.             i = curtrk_pos(s);
  2589.  
  2590.         if (i < 0)
  2591.             return;
  2592.  
  2593.         start_addr = s->trkinfo[i].addr;
  2594.         start_msf.min = s->trkinfo[i].min;
  2595.         start_msf.sec = s->trkinfo[i].sec;
  2596.         start_msf.frame = s->trkinfo[i].frame;
  2597.         s->cur_trk = s->trkinfo[i].trkno;
  2598.         s->cur_idx = 1;
  2599.  
  2600.         /* If the current track has been playing for less
  2601.          * than app_data.prev_threshold blocks, then go
  2602.          * to the beginning of the previous track (if we
  2603.          * are not already on the first track).
  2604.          */
  2605.         go_prev = FALSE;
  2606.         if ((s->cur_tot_addr - start_addr) < app_data.prev_threshold)
  2607.             go_prev = TRUE;
  2608.  
  2609.         if (go_prev) {
  2610.             if (s->prog_tot > 0) {
  2611.                 if (s->prog_cnt > 0) {
  2612.                     s->prog_cnt--;
  2613.                     slioc_new_progshuf = FALSE;
  2614.                 }
  2615.                 if ((i = curprog_pos(s)) < 0)
  2616.                     return;
  2617.  
  2618.                 start_addr = s->trkinfo[i].addr;
  2619.                 start_msf.min = s->trkinfo[i].min;
  2620.                 start_msf.sec = s->trkinfo[i].sec;
  2621.                 start_msf.frame = s->trkinfo[i].frame;
  2622.                 s->cur_trk = s->trkinfo[i].trkno;
  2623.             }
  2624.             else if (s->prog_tot <= 0 && i > 0) {
  2625.                 start_addr = s->trkinfo[i-1].addr;
  2626.                 start_msf.min = s->trkinfo[i-1].min;
  2627.                 start_msf.sec = s->trkinfo[i-1].sec;
  2628.                 start_msf.frame = s->trkinfo[i-1].frame;
  2629.                 s->cur_trk = s->trkinfo[i-1].trkno;
  2630.             }
  2631.         }
  2632.  
  2633.         if (s->mode == M_PAUSE)
  2634.             /* Mute: so we don't get a transient */
  2635.             slioc_mute_on(s);
  2636.  
  2637.         if (s->prog_tot > 0) {
  2638.             /* Program/Shuffle mode: just stop the playback
  2639.              * and let slioc_run_prog go to the previous track
  2640.              */
  2641.             slioc_fake_stop = TRUE;
  2642.  
  2643.             /* Force status update */
  2644.             slioc_get_playstatus(s);
  2645.         }
  2646.         else {
  2647.             end_msf.min = s->tot_min;
  2648.             end_msf.sec = s->tot_sec;
  2649.             end_msf.frame = s->tot_frame;
  2650.  
  2651.             s->cur_tot_addr = start_addr;
  2652.             s->cur_tot_min = start_msf.min;
  2653.             s->cur_tot_sec = start_msf.sec;
  2654.             s->cur_tot_frame = start_msf.frame;
  2655.             s->cur_trk_addr = 0;
  2656.             s->cur_trk_min = s->cur_trk_sec = s->cur_trk_frame = 0;
  2657.  
  2658.             dpy_track(s);
  2659.             dpy_index(s);
  2660.             dpy_time(s, FALSE);
  2661.  
  2662.             if (!slioc_do_playaudio(ADDR_BLK | ADDR_MSF,
  2663.                       start_addr, s->tot_addr,
  2664.                       &start_msf, &end_msf, 0, 0)) {
  2665.                 cd_beep();
  2666.  
  2667.                 /* Restore volume */
  2668.                 slioc_mute_off(s);
  2669.                 return;
  2670.             }
  2671.  
  2672.             if (s->mode == M_PAUSE) {
  2673.                 slioc_pause_resume(FALSE);
  2674.  
  2675.                 /* Restore volume */
  2676.                 slioc_mute_off(s);
  2677.             }
  2678.         }
  2679.  
  2680.         break;
  2681.  
  2682.     case M_STOP:
  2683.         if (s->prog_tot > 0) {
  2684.             /* Pre-selecting tracks not supported in shuffle
  2685.              * or program mode.
  2686.              */
  2687.             cd_beep();
  2688.             return;
  2689.         }
  2690.  
  2691.         /* Find previous track */
  2692.         if (s->cur_trk <= 0) {
  2693.             s->cur_trk = s->trkinfo[0].trkno;
  2694.             dpy_track(s);
  2695.         }
  2696.         else {
  2697.             i = curtrk_pos(s);
  2698.  
  2699.             if (i > 0) {
  2700.                 s->cur_trk = s->trkinfo[i-1].trkno;
  2701.                 dpy_track(s);
  2702.             }
  2703.         }
  2704.         break;
  2705.  
  2706.     default:
  2707.         cd_beep();
  2708.         break;
  2709.     }
  2710. }
  2711.  
  2712.  
  2713. /*
  2714.  * slioc_nexttrk
  2715.  *    Next track function
  2716.  *
  2717.  * Args:
  2718.  *    s - Pointer to the curstat_t structure
  2719.  *
  2720.  * Return:
  2721.  *    Nothing.
  2722.  */
  2723. void
  2724. slioc_nexttrk(curstat_t *s)
  2725. {
  2726.     sword32_t    i;
  2727.     word32_t    start_addr;
  2728.     msf_t        start_msf,
  2729.             end_msf;
  2730.  
  2731.     if (!slioc_disc_ready(s)) {
  2732.         cd_beep();
  2733.         return;
  2734.     }
  2735.  
  2736.     switch (s->mode) {
  2737.     case M_A:
  2738.     case M_AB:
  2739.     case M_SAMPLE:
  2740.         s->mode = M_PLAY;
  2741.         dpy_playmode(s, FALSE);
  2742.         /*FALLTHROUGH*/
  2743.     case M_PLAY:
  2744.     case M_PAUSE:
  2745.         if (s->prog_tot > 0) {
  2746.             if (s->prog_cnt >= s->prog_tot) {
  2747.                 /* Disallow advancing beyond current
  2748.                  * shuffle/program sequence if
  2749.                  * repeat mode is not on.
  2750.                  */
  2751.                 if (s->repeat)
  2752.                     slioc_new_progshuf = TRUE;
  2753.                 else
  2754.                     return;
  2755.             }
  2756.  
  2757.             if (s->mode == M_PAUSE)
  2758.                 /* Mute: so we don't get a transient */
  2759.                 slioc_mute_on(s);
  2760.  
  2761.             /* Program/Shuffle mode: just stop the playback
  2762.              * and let slioc_run_prog go to the next track.
  2763.              */
  2764.             slioc_fake_stop = TRUE;
  2765.  
  2766.             /* Force status update */
  2767.             slioc_get_playstatus(s);
  2768.  
  2769.             return;
  2770.         }
  2771.  
  2772.         /* Find next track */
  2773.         if ((i = curtrk_pos(s)) < 0)
  2774.             return;
  2775.  
  2776.         if (i < (MAXTRACK - 1) &&
  2777.             s->trkinfo[i+1].trkno >= 0 &&
  2778.             s->trkinfo[i+1].trkno != CDROM_LEADOUT) {
  2779.  
  2780.             start_addr = s->trkinfo[i+1].addr;
  2781.             start_msf.min = s->trkinfo[i+1].min;
  2782.             start_msf.sec = s->trkinfo[i+1].sec;
  2783.             start_msf.frame = s->trkinfo[i+1].frame;
  2784.             s->cur_trk = s->trkinfo[i+1].trkno;
  2785.             s->cur_idx = 1;
  2786.  
  2787.             if (s->mode == M_PAUSE)
  2788.                 /* Mute: so we don't get a transient */
  2789.                 slioc_mute_on(s);
  2790.  
  2791.             end_msf.min = s->tot_min;
  2792.             end_msf.sec = s->tot_sec;
  2793.             end_msf.frame = s->tot_frame;
  2794.  
  2795.             s->cur_tot_addr = start_addr;
  2796.             s->cur_tot_min = start_msf.min;
  2797.             s->cur_tot_sec = start_msf.sec;
  2798.             s->cur_tot_frame = start_msf.frame;
  2799.             s->cur_trk_addr = 0;
  2800.             s->cur_trk_min = s->cur_trk_sec = s->cur_trk_frame = 0;
  2801.  
  2802.             dpy_track(s);
  2803.             dpy_index(s);
  2804.             dpy_time(s, FALSE);
  2805.  
  2806.             if (!slioc_do_playaudio(ADDR_BLK | ADDR_MSF,
  2807.                       start_addr, s->tot_addr,
  2808.                       &start_msf, &end_msf, 0, 0)) {
  2809.                 cd_beep();
  2810.                 return;
  2811.             }
  2812.  
  2813.             if (s->mode == M_PAUSE) {
  2814.                 slioc_pause_resume(FALSE);
  2815.  
  2816.                 /* Restore volume */
  2817.                 slioc_mute_off(s);
  2818.             }
  2819.         }
  2820.  
  2821.         break;
  2822.  
  2823.     case M_STOP:
  2824.         if (s->prog_tot > 0) {
  2825.             /* Pre-selecting tracks not supported in shuffle
  2826.              * or program mode.
  2827.              */
  2828.             cd_beep();
  2829.             return;
  2830.         }
  2831.  
  2832.         /* Find next track */
  2833.         if (s->cur_trk <= 0) {
  2834.             s->cur_trk = s->trkinfo[0].trkno;
  2835.             dpy_track(s);
  2836.         }
  2837.         else {
  2838.             i = curtrk_pos(s);
  2839.  
  2840.             if (i >= 0 &&
  2841.                 s->trkinfo[i+1].trkno != CDROM_LEADOUT) {
  2842.                 s->cur_trk = s->trkinfo[i+1].trkno;
  2843.                 dpy_track(s);
  2844.             }
  2845.         }
  2846.         break;
  2847.  
  2848.     default:
  2849.         cd_beep();
  2850.         break;
  2851.     }
  2852. }
  2853.  
  2854.  
  2855. /*
  2856.  * slioc_previdx
  2857.  *    Previous index function
  2858.  *
  2859.  * Args:
  2860.  *    s - Pointer to the curstat_t structure
  2861.  *
  2862.  * Return:
  2863.  *    Nothing.
  2864.  */
  2865. void
  2866. slioc_previdx(curstat_t *s)
  2867. {
  2868.     msf_t        start_msf,
  2869.             end_msf;
  2870.     byte_t        idx;
  2871.  
  2872.     if (s->prog_tot > 0) {
  2873.         /* Index search is not supported in program/shuffle mode */
  2874.         cd_beep();
  2875.         return;
  2876.     }
  2877.  
  2878.     switch (s->mode) {
  2879.     case M_A:
  2880.     case M_AB:
  2881.     case M_SAMPLE:
  2882.         s->mode = M_PLAY;
  2883.         dpy_playmode(s, FALSE);
  2884.         /*FALLTHROUGH*/
  2885.     case M_PLAY:
  2886.     case M_PAUSE:
  2887.         /* Find appropriate index to start */
  2888.         if (s->cur_idx > 1 &&
  2889.             (s->cur_tot_addr - s->sav_iaddr) < app_data.prev_threshold)
  2890.             idx = s->cur_idx - 1;
  2891.         else
  2892.             idx = s->cur_idx;
  2893.         
  2894.         /* This is a Hack...
  2895.          * Since there is no standard command to start
  2896.          * playback on an index boundary and then go on playing
  2897.          * until the end of the disc, we will use the PLAY AUDIO
  2898.          * TRACK/INDEX command to go to where we want to start,
  2899.          * immediately followed by a PAUSE.  We then find the
  2900.          * current block position and issue a PLAY AUDIO MSF
  2901.          * or PLAY AUDIO(12) command to start play there.
  2902.          * We mute the audio in between these operations to
  2903.          * prevent unpleasant transients.
  2904.          */
  2905.  
  2906.         /* Mute */
  2907.         slioc_mute_on(s);
  2908.  
  2909.         if (!slioc_do_playaudio(ADDR_TRKIDX, 0, 0, NULL, NULL,
  2910.                   (byte_t) s->cur_trk, idx)) {
  2911.             /* Restore volume */
  2912.             slioc_mute_off(s);
  2913.             cd_beep();
  2914.             return;
  2915.         }
  2916.  
  2917.         slioc_idx_pause = TRUE;
  2918.  
  2919.         if (!slioc_pause_resume(FALSE)) {
  2920.             /* Restore volume */
  2921.             slioc_mute_off(s);
  2922.             slioc_idx_pause = FALSE;
  2923.             return;
  2924.         }
  2925.  
  2926.         /* Use slioc_get_playstatus to update the current status */
  2927.         if (!slioc_get_playstatus(s)) {
  2928.             /* Restore volume */
  2929.             slioc_mute_off(s);
  2930.             slioc_idx_pause = FALSE;
  2931.             return;
  2932.         }
  2933.  
  2934.         /* Save starting block addr of this index */
  2935.         s->sav_iaddr = s->cur_tot_addr;
  2936.  
  2937.         if (s->mode != M_PAUSE)
  2938.             /* Restore volume */
  2939.             slioc_mute_off(s);
  2940.  
  2941.         start_msf.min = s->cur_tot_min;
  2942.         start_msf.sec = s->cur_tot_sec;
  2943.         start_msf.frame = s->cur_tot_frame;
  2944.         end_msf.min = s->tot_min;
  2945.         end_msf.sec = s->tot_sec;
  2946.         end_msf.frame = s->tot_frame;
  2947.  
  2948.         if (!slioc_do_playaudio(ADDR_BLK | ADDR_MSF,
  2949.                   s->cur_tot_addr, s->tot_addr,
  2950.                   &start_msf, &end_msf, 0, 0)) {
  2951.             cd_beep();
  2952.             slioc_idx_pause = FALSE;
  2953.             return;
  2954.         }
  2955.  
  2956.         slioc_idx_pause = FALSE;
  2957.  
  2958.         if (s->mode == M_PAUSE) {
  2959.             slioc_pause_resume(FALSE);
  2960.  
  2961.             /* Restore volume */
  2962.             slioc_mute_off(s);
  2963.  
  2964.             /* Force update of curstat */
  2965.             slioc_get_playstatus(s);
  2966.         }
  2967.  
  2968.         break;
  2969.  
  2970.     default:
  2971.         cd_beep();
  2972.         break;
  2973.     }
  2974. }
  2975.  
  2976.  
  2977. /*
  2978.  * slioc_nextidx
  2979.  *    Next index function
  2980.  *
  2981.  * Args:
  2982.  *    s - Pointer to the curstat_t structure
  2983.  *
  2984.  * Return:
  2985.  *    Nothing.
  2986.  */
  2987. void
  2988. slioc_nextidx(curstat_t *s)
  2989. {
  2990.     msf_t        start_msf,
  2991.             end_msf;
  2992.  
  2993.     if (s->prog_tot > 0) {
  2994.         /* Index search is not supported in program/shuffle mode */
  2995.         cd_beep();
  2996.         return;
  2997.     }
  2998.  
  2999.     switch (s->mode) {
  3000.     case M_A:
  3001.     case M_AB:
  3002.     case M_SAMPLE:
  3003.         s->mode = M_PLAY;
  3004.         dpy_playmode(s, FALSE);
  3005.         /*FALLTHROUGH*/
  3006.     case M_PLAY:
  3007.     case M_PAUSE:
  3008.         /* Find appropriate index to start */
  3009.         
  3010.         /* This is a Hack...
  3011.          * Since there is no standard command to start
  3012.          * playback on an index boundary and then go on playing
  3013.          * until the end of the disc, we will use the PLAY AUDIO
  3014.          * TRACK/INDEX command to go to where we want to start,
  3015.          * immediately followed by a PAUSE.  We then find the
  3016.          * current block position and issue a PLAY AUDIO MSF
  3017.          * or PLAY AUDIO(12) command to start play there.
  3018.          * We mute the audio in between these operations to
  3019.          * prevent unpleasant transients.
  3020.          */
  3021.  
  3022.         /* Mute */
  3023.         slioc_mute_on(s);
  3024.  
  3025.         if (!slioc_do_playaudio(ADDR_TRKIDX, 0, 0, NULL, NULL,
  3026.                   (byte_t) s->cur_trk,
  3027.                   (byte_t) (s->cur_idx + 1))) {
  3028.             /* Restore volume */
  3029.             slioc_mute_off(s);
  3030.             cd_beep();
  3031.             return;
  3032.         }
  3033.  
  3034.         slioc_idx_pause = TRUE;
  3035.  
  3036.         if (!slioc_pause_resume(FALSE)) {
  3037.             /* Restore volume */
  3038.             slioc_mute_off(s);
  3039.             slioc_idx_pause = FALSE;
  3040.             return;
  3041.         }
  3042.  
  3043.         /* Use slioc_get_playstatus to update the current status */
  3044.         if (!slioc_get_playstatus(s)) {
  3045.             /* Restore volume */
  3046.             slioc_mute_off(s);
  3047.             slioc_idx_pause = FALSE;
  3048.             return;
  3049.         }
  3050.  
  3051.         /* Save starting block addr of this index */
  3052.         s->sav_iaddr = s->cur_tot_addr;
  3053.  
  3054.         if (s->mode != M_PAUSE)
  3055.             /* Restore volume */
  3056.             slioc_mute_off(s);
  3057.  
  3058.         start_msf.min = s->cur_tot_min;
  3059.         start_msf.sec = s->cur_tot_sec;
  3060.         start_msf.frame = s->cur_tot_frame;
  3061.         end_msf.min = s->tot_min;
  3062.         end_msf.sec = s->tot_sec;
  3063.         end_msf.frame = s->tot_frame;
  3064.  
  3065.         if (!slioc_do_playaudio(ADDR_BLK | ADDR_MSF,
  3066.                   s->cur_tot_addr, s->tot_addr,
  3067.                   &start_msf, &end_msf, 0, 0)) {
  3068.             cd_beep();
  3069.             slioc_idx_pause = FALSE;
  3070.             return;
  3071.         }
  3072.  
  3073.         slioc_idx_pause = FALSE;
  3074.  
  3075.         if (s->mode == M_PAUSE) {
  3076.             slioc_pause_resume(FALSE);
  3077.  
  3078.             /* Restore volume */
  3079.             slioc_mute_off(s);
  3080.  
  3081.             /* Force update of curstat */
  3082.             slioc_get_playstatus(s);
  3083.         }
  3084.  
  3085.         break;
  3086.  
  3087.     default:
  3088.         cd_beep();
  3089.         break;
  3090.     }
  3091. }
  3092.  
  3093.  
  3094. /*
  3095.  * slioc_rew
  3096.  *    Search-rewind function
  3097.  *
  3098.  * Args:
  3099.  *    s - Pointer to the curstat_t structure
  3100.  *
  3101.  * Return:
  3102.  *    Nothing.
  3103.  */
  3104. void
  3105. slioc_rew(curstat_t *s, bool_t start)
  3106. {
  3107.     sword32_t    i;
  3108.     msf_t        start_msf,
  3109.             end_msf;
  3110.     byte_t        vol;
  3111.  
  3112.     switch (s->mode) {
  3113.     case M_A:
  3114.     case M_AB:
  3115.     case M_SAMPLE:
  3116.         /* Go to normal play mode first */
  3117.         slioc_play_pause(s);
  3118.  
  3119.         /*FALLTHROUGH*/
  3120.     case M_PLAY:
  3121.     case M_PAUSE:
  3122.         if (start) {
  3123.             /* Button press */
  3124.  
  3125.             if (s->mode == M_PLAY)
  3126.                 slioc_stop_stat_poll();
  3127.  
  3128.             /* Reduce volume */
  3129.             vol = (byte_t) ((int) s->level *
  3130.                 app_data.skip_vol / 100);
  3131.  
  3132.             (void) slioc_cfg_vol((int)
  3133.                 ((vol < (byte_t)app_data.skip_minvol) ?
  3134.                  (byte_t) app_data.skip_minvol : vol),
  3135.                 s,
  3136.                 FALSE,
  3137.                 0
  3138.             );
  3139.  
  3140.             /* Start search rewind */
  3141.             slioc_start_search = TRUE;
  3142.             slioc_run_rew(s);
  3143.         }
  3144.         else {
  3145.             /* Button release */
  3146.  
  3147.             slioc_stop_rew(s);
  3148.  
  3149.             /* Update display */
  3150.             slioc_get_playstatus(s);
  3151.  
  3152.             if (s->mode == M_PAUSE)
  3153.                 /* Mute: so we don't get a transient */
  3154.                 slioc_mute_on(s);
  3155.             else
  3156.                 /* Restore volume */
  3157.                 slioc_mute_off(s);
  3158.  
  3159.             if (s->shuffle || s->program) {
  3160.                 if ((i = curtrk_pos(s)) < 0 ||
  3161.                     s->trkinfo[i].trkno == CDROM_LEADOUT) {
  3162.                     /* Restore volume */
  3163.                     slioc_mute_off(s);
  3164.                     return;
  3165.                 }
  3166.  
  3167.                 start_msf.min = s->cur_tot_min;
  3168.                 start_msf.sec = s->cur_tot_sec;
  3169.                 start_msf.frame = s->cur_tot_frame;
  3170.                 end_msf.min = s->trkinfo[i+1].min;
  3171.                 end_msf.sec = s->trkinfo[i+1].sec;
  3172.                 end_msf.frame = s->trkinfo[i+1].frame;
  3173.  
  3174.                 if (!slioc_do_playaudio(ADDR_BLK | ADDR_MSF,
  3175.                           s->cur_tot_addr,
  3176.                           s->trkinfo[i+1].addr,
  3177.                           &start_msf, &end_msf,
  3178.                           0, 0)) {
  3179.                     cd_beep();
  3180.  
  3181.                     /* Restore volume */
  3182.                     slioc_mute_off(s);
  3183.                     return;
  3184.                 }
  3185.             }
  3186.             else {
  3187.                 start_msf.min = s->cur_tot_min;
  3188.                 start_msf.sec = s->cur_tot_sec;
  3189.                 start_msf.frame = s->cur_tot_frame;
  3190.                 end_msf.min = s->tot_min;
  3191.                 end_msf.sec = s->tot_sec;
  3192.                 end_msf.frame = s->tot_frame;
  3193.  
  3194.                 if (!slioc_do_playaudio(ADDR_BLK | ADDR_MSF,
  3195.                           s->cur_tot_addr,
  3196.                           s->tot_addr,
  3197.                           &start_msf, &end_msf,
  3198.                           0, 0)) {
  3199.                     cd_beep();
  3200.  
  3201.                     /* Restore volume */
  3202.                     slioc_mute_off(s);
  3203.                     return;
  3204.                 }
  3205.             }
  3206.  
  3207.             if (s->mode == M_PAUSE) {
  3208.                 slioc_pause_resume(FALSE);
  3209.  
  3210.                 /* Restore volume */
  3211.                 slioc_mute_off(s);
  3212.             }
  3213.             else
  3214.                 slioc_start_stat_poll(s);
  3215.         }
  3216.         break;
  3217.  
  3218.     default:
  3219.         if (start)
  3220.             cd_beep();
  3221.         break;
  3222.     }
  3223. }
  3224.  
  3225.  
  3226. /*
  3227.  * slioc_ff
  3228.  *    Search-fast-forward function
  3229.  *
  3230.  * Args:
  3231.  *    s - Pointer to the curstat_t structure
  3232.  *
  3233.  * Return:
  3234.  *    Nothing.
  3235.  */
  3236. void
  3237. slioc_ff(curstat_t *s, bool_t start)
  3238. {
  3239.     sword32_t    i;
  3240.     msf_t        start_msf,
  3241.             end_msf;
  3242.     byte_t        vol;
  3243.  
  3244.     switch (s->mode) {
  3245.     case M_A:
  3246.     case M_AB:
  3247.     case M_SAMPLE:
  3248.         /* Go to normal play mode first */
  3249.         slioc_play_pause(s);
  3250.  
  3251.         /*FALLTHROUGH*/
  3252.     case M_PLAY:
  3253.     case M_PAUSE:
  3254.         if (start) {
  3255.             /* Button press */
  3256.  
  3257.             if (s->mode == M_PLAY)
  3258.                 slioc_stop_stat_poll();
  3259.  
  3260.             /* Reduce volume */
  3261.             vol = (byte_t) ((int) s->level *
  3262.                 app_data.skip_vol / 100);
  3263.  
  3264.             (void) slioc_cfg_vol((int)
  3265.                 ((vol < (byte_t)app_data.skip_minvol) ?
  3266.                  (byte_t) app_data.skip_minvol : vol),
  3267.                 s,
  3268.                 FALSE,
  3269.                 0
  3270.             );
  3271.  
  3272.             /* Start search forward */
  3273.             slioc_start_search = TRUE;
  3274.             slioc_run_ff(s);
  3275.         }
  3276.         else {
  3277.             /* Button release */
  3278.  
  3279.             slioc_stop_ff(s);
  3280.  
  3281.             /* Update display */
  3282.             slioc_get_playstatus(s);
  3283.  
  3284.             if (s->mode == M_PAUSE)
  3285.                 /* Mute: so we don't get a transient */
  3286.                 slioc_mute_on(s);
  3287.             else
  3288.                 /* Restore volume */
  3289.                 slioc_mute_off(s);
  3290.  
  3291.             if (s->shuffle || s->program) {
  3292.                 if ((i = curtrk_pos(s)) < 0 ||
  3293.                     s->trkinfo[i].trkno == CDROM_LEADOUT) {
  3294.                     /* Restore volume */
  3295.                     slioc_mute_off(s);
  3296.                     return;
  3297.                 }
  3298.  
  3299.                 start_msf.min = s->cur_tot_min;
  3300.                 start_msf.sec = s->cur_tot_sec;
  3301.                 start_msf.frame = s->cur_tot_frame;
  3302.                 end_msf.min = s->trkinfo[i+1].min;
  3303.                 end_msf.sec = s->trkinfo[i+1].sec;
  3304.                 end_msf.frame = s->trkinfo[i+1].frame;
  3305.  
  3306.                 if (!slioc_do_playaudio(ADDR_BLK | ADDR_MSF,
  3307.                           s->cur_tot_addr,
  3308.                           s->trkinfo[i+1].addr,
  3309.                           &start_msf, &end_msf,
  3310.                           0, 0)) {
  3311.                     cd_beep();
  3312.  
  3313.                     /* Restore volume */
  3314.                     slioc_mute_off(s);
  3315.                     return;
  3316.                 }
  3317.             }
  3318.             else {
  3319.                 start_msf.min = s->cur_tot_min;
  3320.                 start_msf.sec = s->cur_tot_sec;
  3321.                 start_msf.frame = s->cur_tot_frame;
  3322.                 end_msf.min = s->tot_min;
  3323.                 end_msf.sec = s->tot_sec;
  3324.                 end_msf.frame = s->tot_frame;
  3325.  
  3326.                 if (!slioc_do_playaudio(ADDR_BLK | ADDR_MSF,
  3327.                           s->cur_tot_addr,
  3328.                           s->tot_addr,
  3329.                           &start_msf, &end_msf,
  3330.                           0, 0)) {
  3331.                     cd_beep();
  3332.  
  3333.                     /* Restore volume */
  3334.                     slioc_mute_off(s);
  3335.                     return;
  3336.                 }
  3337.             }
  3338.             if (s->mode == M_PAUSE) {
  3339.                 slioc_pause_resume(FALSE);
  3340.  
  3341.                 /* Restore volume */
  3342.                 slioc_mute_off(s);
  3343.             }
  3344.             else
  3345.                 slioc_start_stat_poll(s);
  3346.         }
  3347.         break;
  3348.  
  3349.     default:
  3350.         if (start)
  3351.             cd_beep();
  3352.         break;
  3353.     }
  3354. }
  3355.  
  3356.  
  3357. /*
  3358.  * slioc_warp
  3359.  *    Track warp function
  3360.  *
  3361.  * Args:
  3362.  *    s - Pointer to the curstat_t structure
  3363.  *
  3364.  * Return:
  3365.  *    Nothing.
  3366.  */
  3367. void
  3368. slioc_warp(curstat_t *s)
  3369. {
  3370.     word32_t    start_addr,
  3371.             end_addr;
  3372.     msf_t        start_msf,
  3373.             end_msf;
  3374.     int        i;
  3375.  
  3376.     start_addr = s->cur_tot_addr;
  3377.     start_msf.min = s->cur_tot_min;
  3378.     start_msf.sec = s->cur_tot_sec;
  3379.     start_msf.frame = s->cur_tot_frame;
  3380.  
  3381.     switch (s->mode) {
  3382.     case M_A:
  3383.     case M_AB:
  3384.     case M_SAMPLE:
  3385.         /* Go to normal play mode first */
  3386.         slioc_play_pause(s);
  3387.  
  3388.         /*FALLTHROUGH*/
  3389.     case M_PLAY:
  3390.     case M_PAUSE:
  3391.         if (s->shuffle || s->program) {
  3392.             if ((i = curtrk_pos(s)) < 0) {
  3393.                 cd_beep();
  3394.                 return;
  3395.             }
  3396.  
  3397.             end_addr = s->trkinfo[i+1].addr;
  3398.             end_msf.min = s->trkinfo[i+1].min;
  3399.             end_msf.sec = s->trkinfo[i+1].sec;
  3400.             end_msf.frame = s->trkinfo[i+1].frame;
  3401.         }
  3402.         else {
  3403.             end_addr = s->tot_addr;
  3404.             end_msf.min = s->tot_min;
  3405.             end_msf.sec = s->tot_sec;
  3406.             end_msf.frame = s->tot_frame;
  3407.         }
  3408.  
  3409.         if (s->mode == M_PAUSE)
  3410.             /* Mute: so we don't get a transient */
  3411.             slioc_mute_on(s);
  3412.  
  3413.         if (!slioc_do_playaudio(ADDR_BLK | ADDR_MSF,
  3414.                   start_addr, end_addr,
  3415.                   &start_msf, &end_msf,
  3416.                   0, 0)) {
  3417.             cd_beep();
  3418.  
  3419.             /* Restore volume */
  3420.             slioc_mute_off(s);
  3421.             return;
  3422.         }
  3423.  
  3424.         if (s->mode == M_PAUSE) {
  3425.             slioc_pause_resume(FALSE);
  3426.  
  3427.             /* Restore volume */
  3428.             slioc_mute_off(s);
  3429.         }
  3430.  
  3431.         break;
  3432.  
  3433.     default:
  3434.         break;
  3435.     }
  3436. }
  3437.  
  3438.  
  3439. /*
  3440.  * slioc_mute_on
  3441.  *    Mute audio function
  3442.  *
  3443.  * Args:
  3444.  *    s - Pointer to the curstat_t structure
  3445.  *
  3446.  * Return:
  3447.  *    Nothing.
  3448.  */
  3449. void
  3450. slioc_mute_on(curstat_t *s)
  3451. {
  3452.     (void) slioc_cfg_vol(0, s, FALSE, 0);
  3453. }
  3454.  
  3455.  
  3456. /*
  3457.  * slioc_mute_off
  3458.  *    Un-mute audio function
  3459.  *
  3460.  * Args:
  3461.  *    s - Pointer to the curstat_t structure
  3462.  *
  3463.  * Return:
  3464.  *    Nothing.
  3465.  */
  3466. void
  3467. slioc_mute_off(curstat_t *s)
  3468. {
  3469.     (void) slioc_cfg_vol((int) s->level, s, FALSE, 0);
  3470. }
  3471.  
  3472.  
  3473. /*
  3474.  * slioc_start
  3475.  *    Start the SunOS/Linux ioctl method.
  3476.  *
  3477.  * Args:
  3478.  *    s - Pointer to the curstat_t structure
  3479.  *
  3480.  * Return:
  3481.  *    Nothing.
  3482.  */
  3483. void
  3484. slioc_start(curstat_t *s)
  3485. {
  3486.     /* Check to see if disc is ready */
  3487.     (void) slioc_disc_ready(s);
  3488.  
  3489.     /* Update display */
  3490.     dpy_all(s);
  3491. }
  3492.  
  3493.  
  3494. /*
  3495.  * slioc_icon
  3496.  *    Handler for main window iconification/de-iconification
  3497.  *
  3498.  * Args:
  3499.  *    s - Pointer to the curstat_t structure
  3500.  *    iconified - Whether the main window is iconified
  3501.  *
  3502.  * Return:
  3503.  *    Nothing.
  3504.  */
  3505. void
  3506. slioc_icon(curstat_t *s, bool_t iconified)
  3507. {
  3508.     /* This function attempts to reduce the status polling frequency
  3509.      * when possible to cut down on CPU and bus usage.  This is
  3510.      * done when the CD player is iconified.
  3511.      */
  3512.  
  3513.     /* Increase status polling interval by 4 seconds when iconified */
  3514.     if (iconified)
  3515.         slioc_stat_interval = app_data.stat_interval + 4000;
  3516.     else
  3517.         slioc_stat_interval = app_data.stat_interval;
  3518.  
  3519.     /* Check disc status */
  3520.     if (!slioc_disc_ready(s))
  3521.         return;
  3522.  
  3523.     switch (s->mode) {
  3524.     case M_STOP:
  3525.     case M_NODISC:
  3526.     case M_PAUSE:
  3527.         break;
  3528.  
  3529.     case M_A:
  3530.     case M_AB:
  3531.     case M_SAMPLE:
  3532.         /* No optimization in these modes */
  3533.         slioc_stat_interval = app_data.stat_interval;
  3534.         break;
  3535.  
  3536.     case M_PLAY:
  3537.         if (!iconified) {
  3538.             /* Force an immediate update */
  3539.             slioc_stop_stat_poll();
  3540.             slioc_start_stat_poll(s);
  3541.         }
  3542.         break;
  3543.     }
  3544. }
  3545.  
  3546.  
  3547. /*
  3548.  * slioc_halt
  3549.  *    Shut down the SunOS/Linux ioctl method.
  3550.  *
  3551.  * Args:
  3552.  *    s - Pointer to the curstat_t structure
  3553.  *
  3554.  * Return:
  3555.  *    Nothing.
  3556.  */
  3557. void
  3558. slioc_halt(curstat_t *s)
  3559. {
  3560.     int    i;
  3561.  
  3562.     if (s->mode != M_NODISC) {
  3563.         if (app_data.exit_eject && app_data.eject_supp) {
  3564.             /* User closing application: Eject disc */
  3565.             slioc_start_stop(FALSE, TRUE);
  3566.         }
  3567.         else {
  3568.             if (app_data.exit_stop)
  3569.                 /* User closing application: Stop disc */
  3570.                 slioc_start_stop(FALSE, FALSE);
  3571.  
  3572.             switch (s->mode) {
  3573.             case M_PLAY:
  3574.             case M_PAUSE:
  3575.             case M_A:
  3576.             case M_AB:
  3577.             case M_SAMPLE:
  3578.                 slioc_stop_stat_poll();
  3579.                 break;
  3580.             }
  3581.         }
  3582.     }
  3583.  
  3584.     /* Close device */
  3585.     slioc_close();
  3586. }
  3587.  
  3588.  
  3589. /*
  3590.  * slioc_mode
  3591.  *    Return a text string indicating the current method.
  3592.  *
  3593.  * Args:
  3594.  *    Nothing.
  3595.  *
  3596.  * Return:
  3597.  *    Method text string.
  3598.  */
  3599. char *
  3600. slioc_mode(void)
  3601. {
  3602. #ifdef linux
  3603.     return ("Linux ioctl method");
  3604. #else
  3605.     return ("SunOS ioctl method");
  3606. #endif
  3607. }
  3608.  
  3609.  
  3610. /*
  3611.  * slioc_vers
  3612.  *    Return a text string indicating the method's version number.
  3613.  *
  3614.  * Args:
  3615.  *    Nothing.
  3616.  *
  3617.  * Return:
  3618.  *    Version text string.
  3619.  */
  3620. char *
  3621. slioc_vers(void)
  3622. {
  3623.     return ("");
  3624. }
  3625.  
  3626. #endif    /* DI_SLIOC DEMO_ONLY */
  3627.  
  3628.